牛客算法_数组
1、 两个有序int数组合并到其中一个(重要)
给出一个有序的整数数组 A 和有序的整数数组 B ,请将数组 B 合并到数组 A 中,变成一个有序的升序数组
数据范围: 0≤n,m≤1000≤n,m≤100,∣Ai∣<=100∣Ai∣<=100, ∣Bi∣<=100∣Bi∣<=100
注意:
1.保证 A 数组有足够的空间存放 B 数组的元素, A 和 B 中初始的元素数目分别为 m 和 n,A的数组空间大小为 m+n2.不要返回合并的数组,将数组 B 的数据合并到 A 里面就好了,且后台会自动将合并后的数组 A 的内容打印出来,所以也不需要自己打印
3. A 数组在[0,m-1]的范围也是有序的
思路:从后往前判断 int index = m+n-1
如果是从前往后判断,对于A是空集合的情况, 本地调试时,又不好把A做扩容。不妨直接利用系统已经扩容好的结果,从最大下标开始判断。
public void merge(int A[], int m, int B[], int n) {int a = m - 1, b = n - 1, index = m + n - 1;while (index >= 0) {if (a < 0 || b < 0) A[index--] = a < 0 ? B[b--] : A[a--];else A[index--] = A[a] < B[b] ? B[b--] : A[a--];}}
2、区间合并
思路:
1. 区间排序:先判断start是否相等, 相等的话判断end, 不相等则直接返回比较结果。
public ArrayList<Interval> merge(ArrayList<Interval> intervals) {if (intervals.size() <= 1) {return intervals;}intervals.sort(new Comparator<Interval>() {@Overridepublic int compare(Interval o1, Interval o2) {if (o1.start == o2.start) {// 注意升序的写法return o1.end - o2.end > 0 ? 1 : -1;} else {return o1.start - o2.start > 0 ? 1 : -1;}}});ArrayList<Interval> list = new ArrayList<>();int start = intervals.get(0).start;int end = intervals.get(0).end;for (int i = 1; i < intervals.size(); i++) {// 为一个区间if (intervals.get(i).start > end) {Interval interval = new Interval(start, end);list.add(interval);start = intervals.get(i).start;end = intervals.get(i).end;} else {end = Math.max(intervals.get(i).end, end);}}list.add(new Interval(start, end));return list;}
3. 最长无重复子数组(重要)
给定一个长度为n的数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。
子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组
数据范围:0≤arr.length≤1050≤arr.length≤105,0<arr[i]≤1050<arr[i]≤10
思路1:(滑动窗口思想)
1. 遍历数组,在每个位置 判断当前元素是否和已遍历过的集合元素是否有重复; 用集合保存已经遍历过的元素
2. 如果有重复,将重复元素以及之前的元素从集合删除掉; 从重复元素后的位置开始计算新的子数组长度。
3. 将当前元素加入到集合中
4. 每判断完一个元素后,计算当前的最大子数组长度。
public int maxLength(int[] arr) {if (arr == null || arr.length == 0) {return 0;}if (arr.length == 1) {return 1;}Set<Integer> set = new LinkedHashSet<>();int index = 0; //记录最长无重复子数组 的开始索引int max = 0;for (int i = 0; i < arr.length; i++) {while (set.contains(arr[i])) {// 存在重复元素,就将重复元素下标及其之前的元素全部删掉; // 从重复下标后的元素重新判断子数组set.remove(arr[index++]);}set.add(arr[i]); //添加arr[i]max = Math.max(max, i - index + 1); //取最大值}return max;}
思路2:
暴力破解法, 双循环遍历,利用List统计当前遍历的元素,判断下一个元素再List中是否存在。
缺点:不满足时间限制
public int maxLength(int[] arr) {if (arr == null || arr.length == 0) {return 0;}if (arr.length == 1) {return 1;}int maxLength = 1;for (int i = 0; i < arr.length - 1; i++) {List<Integer> list = new ArrayList<>();list.add(arr[i]);for (int j = i + 1; j < arr.length; j++) {if (list.contains(arr[j])) {maxLength = Math.max(maxLength, j - i );break;} else if (j == arr.length - 1) {maxLength = Math.max(maxLength, j - i + 1 );}list.add(arr[j]);}}return maxLength;}
4. 计算最大面积
给定一个数组height,长度为n,每个数代表坐标轴中的一个点的高度,height[i]是在第i点的高度,请问,从中选2个高度与x轴组成的容器最多能容纳多少水
1.你不能倾斜容器
2.当n小于2时,视为不能形成容器,请返回0
3.数据保证能容纳最多的水不会超过整形范围,即不会超过231-1
思路:这主要是一个数学问题
面积 = b * min{l, r} , b是间距, l, r是两个高度。
移动之前的面积 area = b * min{l, r}。
移动之后的面积 area' = b' * min{l', r'}
关键是看移动长边还是短边,老找到最大的area, 暂时没有想明白移动的思路,先这样把~
public int maxArea(int[] height) {if (height == null || height.length < 2) {return 0;}int left = 0, right = height.length - 1;int res = 0, tmp;while (left < right) {tmp = Math.min(height[left], height[right]) * (right - left);res = res > tmp ? res : tmp;if (height[left] < height[right]) ++left;else --right;}return res;}