leetcode 数组array
二维数组初始化:
int[][] a = {{1,3},{2,6},{8,10},{15,18}};
120. Triangle
给出一个三角形(数据数组),找出从上往下的最小路径和。每一步只能移动到下一行中的相邻结点上。
解法,自底向上
The idea is simple.
-
Go from bottom to top.
-
We start form the row above the bottom row [size()-2].
-
Each number add the smaller number of two numbers that below it.
-
And finally we get to the top we the smallest sum.
public int minimumTotal(List<List<Integer>> triangle) { for(int i = triangle.size() - 2; i >= 0; i--) for(int j = 0; j <= i; j++) triangle.get(i).set(j, triangle.get(i).get(j) + Math.min(triangle.get(i + 1).get(j), triangle.get(i + 1).get(j + 1))); return triangle.get(0).get(0); }
Boyer-Moore majority vote algorithm(摩尔投票算法)
简介
Boyer-Moore majority vote algorithm(摩尔投票算法)是一种在线性时间O(n)和空间复杂度的情况下,在一个元素序列中查找包含最多的元素。它是以Robert S.Boyer和J Strother Moore命名的,1981年发明的,是一种典型的流算法(streaming algorithm)。
在它最简单的形式就是,查找最多的元素,也就是在输入中重复出现超过一半以上(n/2)的元素。如果序列中没有最多的元素,算法不能检测到正确结果,将输出其中的一个元素之一。
当元素重复的次数比较小的时候,对于流算法不能在小于线性空间的情况下查找频率最高的元素。
算法描述
算法在局部变量中定义一个序列元素(m)和一个计数器(i),初始化的情况下计数器为0. 算法依次扫描序列中的元素,当处理元素x的时候,如果计数器为0,那么将x赋值给m,然后将计数器(i)设置为1,如果计数器不为0,那么将序列元素m和x比较,如果相等,那么计数器加1,如果不等,那么计数器减1。处理之后,最后存储的序列元素(m),就是这个序列中最多的元素。
如果不确定是否存储的元素m是最多的元素,还可以进行第二遍扫描判断是否为最多的元素。
perudocode
- Initialize an element m and a counter i with i = 0
- For each element x of the input sequence:
- if i = 0, then assign m = x and i = 1
- else if m = x, then assign i = i + 1
- else assign i = i − 1
- Return m
问题1:数组中存在元素出现次数大于 ⌊ n/2 ⌋ ,求该元素
上面方法即可
问题2:数组中是否存在元素出现次数大于 ⌊ n/2 ⌋
用上面找到的摩尔投票算法,第一遍扫描输出一个存储的元素,然后还需要进行第二遍扫描来判断元素在序列中是否确实超过n/2了。 因为一个元素超过一半,最后肯定会留下,但是最后留下的不一定超过一半,所以要扫描第二遍。
229. Majority Element II
求出现次数大于n/3的众数,而且限定了时间和空间复杂度,那么就不能排序,也不能使用哈希表,这么苛刻的限制条件只有一种方法能解了,那就是摩尔投票法 Moore Voting
我们先考虑可能会有多少个众数,经过举了很多例子分析得出,任意一个数组出现次数大于n/3的众数最多有两个
我们使用投票法的核心是找出两个候选众数进行投票,需要两遍遍历,第一遍历找出两个候选众数,第二遍遍历重新投票验证这两个候选众数是否为众数即可,选候选众数方法和前面那篇Majority Element 求众数一样,由于之前那题题目中限定了一定会有众数存在,故而省略了验证候选众数的步骤,这道题却没有这种限定,即满足要求的众数可能不存在,所以要有验证。
public List<Integer> majorityElement(int[] nums) { if (nums == null || nums.length == 0) return new ArrayList<Integer>(); List<Integer> result = new ArrayList<Integer>(); int number1 = nums[0], number2 = nums[0], count1 = 0, count2 = 0, len = nums.length; for (int i = 0; i < len; i++) { if (nums[i] == number1) count1++; else if (nums[i] == number2) count2++; else if (count1 == 0) { number1 = nums[i]; count1 = 1; } else if (count2 == 0) { number2 = nums[i]; count2 = 1; } else { count1--;//不属于这两个,都要减一 count2--; } } count1 = 0; count2 = 0; for (int i = 0; i < len; i++) { if (nums[i] == number1) count1++; else if (nums[i] == number2) count2++; } if (count1 > len / 3) result.add(number1); if (count2 > len / 3) result.add(number2); return result; }
旋转数组的最小数字
采用二分法解答这个问题,
mid = low + (high - low)/2
需要考虑三种情况:
(1)array[mid] > array[high]:
出现这种情况的array类似[3,4,5,6,0,1,2],此时最小数字一定在mid的右边。
low = mid + 1
(2)array[mid] == array[high]:
出现这种情况的array类似 [1,0,1,1,1] 或者[1,1,1,0,1],此时最小数字不好判断在mid左边
还是右边,这时只好一个一个试 ,
high = high - 1
(3)array[mid] < array[high]:
出现这种情况的array类似[2,2,3,4,5,6,6],此时最小数字一定就是array[mid]或者在mid的左
边。因为右边必然都是递增的。
high = mid
注意这里有个坑:如果待查询的范围最后只剩两个数,那么mid 一定会指向下标靠前的数字
比如 array = [4,6]
array[low] = 4 ;array[mid] = 4 ; array[high] = 6 ;
如果high = mid - 1,就会产生错误, 因此high = mid
但情形(1)中low = mid + 1就不会错误
import java.util.ArrayList; public class Solution { public int minNumberInRotateArray(int [] array) { int low = 0 ; int high = array.length - 1; while(low < high){ int mid = low + (high - low) / 2; if(array[mid] > array[high]){ low = mid + 1; }else if(array[mid] == array[high]){ high = high - 1; }else{ high = mid; } } return array[low]; } }
//旋转二分查找目标值 public int search(int[] nums, int target) { int length=nums.length; if(length<=0) return -1; int low=0; int high=length-1; int mid=-1; while (low<=high){ mid=(low+high)/2; if(target==nums[mid]) { return mid; }else { if(nums[mid]<nums[high]){ if(nums[mid]<target&&nums[high]>=target) low=mid+1; else high=mid-1; }else { if(nums[low]<=target&&nums[mid]>target) high=mid-1; else low=mid+1; } } } return -1; } }
任务列表(360公司2017春招真题)
现在现在有一台机器,这台机器可以接收两种形式任务:(1)任务列表,任务列表里面有N个任务,对于第i个任务,机器在Ti时间开始执行,并在1个单位时间内做完。(2)临时任务,机器可以在任意时间接收一个临时任务,但任务列表里面的任务优先级要高于临时任务,也就是说当机器空闲的时候才会执行临时任务。
现在机器已经接收一个任务列表。接下来会有M个临时任务,我们想知道每个临时任务何时被执行。为了简化问题我们可以认为这M个临时任务是独立无关即任务是可以同时执行的,互不影响的。
输入
输入数据有多组,每组数据第一行包括两个整数N和M(1<=N, M<=10^5)。
接下来一行有N个不同数字T1,T2,T3.....TN(1<=T1
接下来又M行,每行一个数字Qi(1<=Qi<=10^9),表示第i个临时任务的的接收时间。
输出
对于每个临时任务,输出它被执行的时间。
样例输入
5 6
1 2 3 5 6
3
2
1
4
5
6
样例输出
4
4
4
4
7
7
将不能执行的时间标出来 对于每个临时任务往后找出一个可以执行的时间
public static void main(String[] args) { Scanner cin = new Scanner(System.in); int n = cin.nextInt(); int m = cin.nextInt(); int[] gap = new int[100000]; for (int i = 0; i < n; i++) { int temp = cin.nextInt(); gap[temp] = 1; } int[] result = new int[m]; for (int i = 0; i < m; i++) { int temp = cin.nextInt(); for (int j = temp; j < gap.length; j++) { if (gap[j] != 1) { result[i] = j; break; } } } for (int i = 0; i < result.length; i++) { System.out.println(result[i]); } }
56. Merge Intervals
先把第一个区间加入结果集,在循环中如果更新了第一个区间的max interval[1],result的第一个interval也会随之更新
public int[][] merge(int[][] intervals) { if (intervals.length <= 1) return intervals; // Sort by ascending starting point Arrays.sort(intervals, (i1, i2) -> Integer.compare(i1[0], i2[0])); List<int[]> result = new ArrayList<>(); int[] newInterval = intervals[0]; result.add(newInterval); for (int[] interval : intervals) { if (interval[0] <= newInterval[1]) // Overlapping intervals, move the end if needed newInterval[1] = Math.max(newInterval[1], interval[1]); else { // Disjoint intervals, add the new interval to the list newInterval = interval; result.add(newInterval); } } return result.toArray(new int[result.size()][]); }