数组类型
数组类型题目一般可以考虑排序来帮助
相关题目 两数之和 1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public int [] twoSum(int [] nums, int target) { Map<Integer,Integer> map = new HashMap <>(); for (int i=0 ;i<nums.length;i++){ Integer has = map.get(target-nums[i]); if (has!=null ) return new int []{has,i}; map.put(nums[i],i); } return new int [0 ]; } }
三数之和 解题思路
排序+指针移动
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { public List<List<Integer>> threeSum (int [] nums) { int n = nums.length; Arrays.sort(nums); List<List<Integer>> ans = new ArrayList <List<Integer>>(); for (int first = 0 ; first < n; ++first) { if (first > 0 && nums[first] == nums[first - 1 ]) { continue ; } int third = n - 1 ; int target = -nums[first]; for (int second = first + 1 ; second < n; ++second) { if (second > first + 1 && nums[second] == nums[second - 1 ]) { continue ; } while (second < third && nums[second] + nums[third] > target) { --third; } if (second == third) { break ; } if (nums[second] + nums[third] == target) { List<Integer> list = new ArrayList <Integer>(); list.add(nums[first]); list.add(nums[second]); list.add(nums[third]); ans.add(list); } } } return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public static List<List<Integer>> threeSum (int [] nums) { List<List<Integer>> ans = new ArrayList (); int len = nums.length; if (nums == null || len < 3 ) return ans; Arrays.sort(nums); for (int i = 0 ; i < len ; i++) { if (nums[i] > 0 ) break ; if (i > 0 && nums[i] == nums[i-1 ]) continue ; int L = i+1 ; int R = len-1 ; while (L < R){ int sum = nums[i] + nums[L] + nums[R]; if (sum == 0 ){ ans.add(Arrays.asList(nums[i],nums[L],nums[R])); while (L<R && nums[L] == nums[L+1 ]) L++; while (L<R && nums[R] == nums[R-1 ]) R--; L++; R--; } else if (sum < 0 ) L++; else if (sum > 0 ) R--; } } return ans; } }
四数之和 字符串相加(easy) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public String addStrings (String num1, String num2) { int length = Math.max(num1.length(),num2.length())+1 ; int [] arr1 = new int [length]; int [] arr2 = new int [length]; for (int i = 0 ,j = num1.length()-1 ; j >= 0 ; i++,j--) arr1[i] = num1.charAt(j)-48 ; for (int i = 0 ,j = num2.length()-1 ; j >= 0 ; i++,j--) arr2[i] = num2.charAt(j)-48 ; StringBuilder sb = new StringBuilder (); int verb = 0 ; for (int i = 0 ; i < length; i++) { int sum = arr1[i] + arr2[i] + verb; if (sum>9 ){ verb=1 ; sum-=10 ; }else verb=0 ; sb.append(sum); } sb.reverse(); if (sb.charAt(0 )=='0' )sb.deleteCharAt(0 ); return sb.toString(); } }
大整数相加(easy) 解题思路: 使用数组存储 我们以 426 709 752 31 8 + 95481 253 129 为例,来看看大整数相加的详细步骤。 第1步, 创建两个整型数组,数组长度是较大整数的位数+1。把每一个整数倒序存储到数组中,整数的个位存于数组下标为0的位置,最高位存于数组的尾部。之所以倒序存储,是因为这样更符合从左到右访问数组的习惯。 第2步, 创建结果数组,结果数组的长度同样是较大整数的位数+1,+1的目的很明显,是给最高位进位预留的。 第3步, 遍历两个数组,从左到右按照对应下标把元素两两相加,就像小学生计算竖式一样。 在本示例中,最先相加的是数组A的第1个元素8和数组B的第1个元素9,结果是7,进位1。把7填充到result数组的对应下标位置,进位的1填充到下一个位置。 第2组相加的是数组A的第2个元素1和数组B的第2个元素2,结果是3, 再加上刚才的进位1,把4填充到result数组的对应下标位置。 第3组相加的是数组A的第3个元素3和数组B的第3个元素1,结果是4,把4填充到result数组的对应下标位置。 第4组相加的是数组A的第4个元素2和数组B的第4个元素3,结果是5,把5填充到result数组的对应下标位置。 以此类推……一直把数组的所有元素都相加完毕。 第4步, 把result数组的全部元素再次逆序,去掉首位的0,就是最终结果。 需要说明的是,为两个大整数建立临时数组,是一种直观的解决方案。若想节省内存空间,也可以不创建这两个临时数组。 代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { public static String bigNumberSum (String bigNumberA, String bigNumberB) { int maxLength = bigNumberA.length() > bigNumberB.length() ? bigNumberA.length() : bigNumberB.length(); int [] arrayA = new int [maxLength + 1 ]; for (int i = 0 ; i < bigNumberA.length(); i++) { arrayA[i] = bigNumberA.charAt(bigNumberA.length() - 1 - i) - '0' ; } int [] arrayB = new int [maxLength + 1 ]; for (int i = 0 ; i < bigNumberB.length(); i++) { arrayB[i] = bigNumberA.charAt(bigNumberB.length() - 1 - i) - '0' ; } int [] result = new int [maxLength + 1 ]; for (int i = 0 ; i < result.length; i++) { int temp = result[i]; temp += arrayA[i]; temp += arrayB[i]; if (temp > 10 ) { temp = temp - 10 ; result[i + 1 ] = 1 ; } result[i] = temp; } StringBuilder sb = new StringBuilder (); boolean findFirst = false ; for (int i = result.length - 1 ; i >= 0 ; i--) { if (!findFirst) { if (result[i] == 0 ) continue ; findFirst = true ; } sb.append(result[i]); } return sb.toString(); } }
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 示例: 输入: [0,1,0,3,12] 输出: [1,3,12,0,0] 说明: 必须在原数组上操作,不能拷贝额外的数组。 尽量减少操作次数。
解题思路
使用双指针,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。 右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移。 注意到以下性质:
左指针左边均为非零数;
右指针左边直到左指针处均为零。 因此每次交换,都是将左指针的零与右指针的非零数交换,且非零数的相对顺序并未改变1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution { public void moveZeroes (int [] nums) { int n = nums.length, left = 0 , right = 0 ; while (right < n) { if (nums[right] != 0 ) { swap(nums, left, right); left++; } right++; } } public void swap (int [] nums, int left, int right) { int temp = nums[left]; nums[left] = nums[right]; nums[right] = temp; } }
盛最多水的容器(简单) 解题思路
1.采用两层循环,时间复杂度O(n^2) 2.双指针首尾比较,如果比当前的高度小直接跳过比较(过滤),否则进行运算比较
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class Solution { public int maxArea (int [] height) { int l = 0 , r = height.length - 1 ; int ans = 0 ; while (l < r) { int area = Math.min(height[l], height[r]) * (r - l); ans = Math.max(ans, area); if (height[l] <= height[r]) { ++l; } else { --r; } } return ans; } }
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { public void rotate (int [] nums, int k) { for (int i = k; i > 0 ; i--) { int last = nums[nums.length - 1 ]; for (int j = nums.length - 1 ; j > 0 ; j--) { nums[j] = nums[j - 1 ]; } nums[0 ] = last; } } public void rotate (int [] nums, int k) { int [] arr = new int [nums.length]; for (int i = 0 ; i < nums.length; i++) { arr[(i + k) % nums.length] = nums[i]; } for (int i = 0 ; i < nums.length; i++) nums[i] = arr[i]; } public void rotate (int [] nums, int k) { k %= nums.length; reverse(nums, 0 , nums.length - 1 ); reverse(nums, 0 , k - 1 ); reverse(nums, k, nums.length - 1 ); } public void reverse (int [] nums, int start, int end) { while (start < end) { int temp = nums[start]; nums[start] = nums[end]; nums[end] = temp; start++; end--; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { public void rotate (int [][] matrix) { int n = matrix.length; for (int i = 0 ; i < n / 2 ; ++i) { for (int j = 0 ; j < (n + 1 ) / 2 ; ++j) { int temp = matrix[i][j]; matrix[i][j] = matrix[n - j - 1 ][i]; matrix[n - j - 1 ][i] = matrix[n - i - 1 ][n - j - 1 ]; matrix[n - i - 1 ][n - j - 1 ] = matrix[j][n - i - 1 ]; matrix[j][n - i - 1 ] = temp; } } } public void rotate (int [][] matrix) { int n = matrix.length; for (int i = 0 ;i < n;i ++) for (int j = 0 ;j < i;j ++){ int temp = matrix[i][j]; matrix[i][j] = matrix[j][i]; matrix[j][i] = temp; } for (int i = 0 ;i < n;i ++) for (int j = 0 , k = n - 1 ; j < k ; j++, k--){ int temp = matrix[i][k]; matrix[i][k] = matrix[i][j]; matrix[i][j] = temp; } } }
1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public int [] plusOne(int [] digits) { for (int i = digits.length - 1 ; i >= 0 ; i--) { digits[i]++; digits[i] = digits[i] % 10 ; if (digits[i] != 0 ) return digits; } digits = new int [digits.length + 1 ]; digits[0 ] = 1 ; return digits; } }
方法:双指针法
数组完成排序后,我们可以放置两个指针 i 和 j,其中 i 是慢指针,而 j 是快指针。只要 nums[i] = nums[j],我们就增加 j 以跳过重复项。 当我们遇到 nums[j]!=nums[i] 时,跳过重复项的运行已经结束,因此我们必须把它(nums[j])的值复制到 nums[i+1]。然后递增 i,接着我们将再次重复相同的过程,直到 j 到达数组的末尾为止。
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution { public int removeDuplicates (int [] nums) { if (nums.length == 0 ) return 0 ; int i = 0 ; for (int j = 1 ; j < nums.length; j++) { if (nums[j] != nums[i]) { i++; nums[i] = nums[j]; } } return i + 1 ; } }
复杂度分析 时间复杂度:O(n),假设数组的长度是 n,那么 i 和 j 分别最多遍历 n 步。 空间复杂度:O(1)。
题目描述
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。
解题思路
代码实现
根据身高重建队列(中等) https://leetcode-cn.com/problems/queue-reconstruction-by-height/
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 思路:对数组进行降序排序,身高高在前面,在对比进行插入class Solution { public int [][] reconstructQueue(int [][] people) { if (0 == people.length || 0 == people[0 ].length)return new int [0 ][0 ]; Arrays.sort(people, new Comparator <int []>() { @Override public int compare (int [] o1, int [] o2) { return o1[0 ] == o2[0 ] ? o1[1 ] - o2[1 ] : o2[0 ] - o1[0 ]; } }); List<int []> list = new ArrayList <>(); for (int [] i : people) { list.add(i[1 ], i); } return list.toArray(new int [list.size()][]); } }
合并两个有序数组(easy) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution { public void merge (int [] nums1, int m, int [] nums2, int n) { int [] ans = new int [m+n]; int i1 = 0 ,i2 = 0 ,i3 = 0 ; while (i1<m&&i2<n){ if (nums1[i1]<nums2[i2]){ ans[i3]=nums1[i1]; i1++; }else { ans[i3]=nums2[i2]; i2++; } i3++; } if (i1==m){ for (int i=i2;i<n;i++){ ans[i3]=nums2[i]; i3++; } }else if (i2==n){ for (int i=i1;i<m;i++){ ans[i3]=nums1[i]; i3++; } } for (int i=0 ;i<ans.length;i++)nums1[i]=ans[i]; } }
合并区间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public int [][] merge0(int [][] intervals) { if (intervals.length == 0 ) { return new int [0 ][2 ]; } Arrays.sort(intervals, new Comparator <int []>() { public int compare (int [] interval1, int [] interval2) { return interval1[0 ] - interval2[0 ]; } }); List<int []> merged = new ArrayList <int []>(); for (int i = 0 ; i < intervals.length; ++i) { int L = intervals[i][0 ], R = intervals[i][1 ]; if (merged.size() == 0 || merged.get(merged.size() - 1 )[1 ] < L) { merged.add(new int []{L, R}); } else { merged.get(merged.size() - 1 )[1 ] = Math.max(merged.get(merged.size() - 1 )[1 ], R); } } return merged.toArray(new int [merged.size()][]); } }
螺旋矩阵 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public List<Integer> spiralOrder (int [][] matrix) { List<Integer> order = new ArrayList <Integer>(); if (matrix == null || matrix.length == 0 || matrix[0 ].length == 0 ) return order; int rows = matrix.length, columns = matrix[0 ].length; int left = 0 , right = columns - 1 , top = 0 , bottom = rows - 1 ; while (left <= right && top <= bottom) { for (int column = left; column <= right; column++) order.add(matrix[top][column]); for (int row = top + 1 ; row <= bottom; row++) order.add(matrix[row][right]); if (left < right && top < bottom) { for (int column = right - 1 ; column > left; column--) order.add(matrix[bottom][column]); for (int row = bottom; row > top; row--)order.add(matrix[row][left]); } left++; right--; top++; bottom--; } return order; } }
螺旋矩阵II 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution { public int [][] generateMatrix(int n) { int [][] arr = new int [n][n]; int left = 0 ,right = n-1 ,up = 0 ,down = n-1 ,num = 0 ; while (left<=right||up<down){ for (int i=left;i<=right;i++)arr[up][i] = ++num; up++; for (int i=up;i<=down;i++)arr[i][right] = ++num; right--; for (int i=right;i>=left;i--)arr[down][i] = ++num; down--; for (int i=down;i>=up;i--)arr[i][left] = ++num; left++; } return arr; } }
接雨水 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public int trapbf (int [] height) { int ans = 0 ; for (int i=0 ;i<height.length;i++){ int leftMax = 0 ; int rightMax = 0 ; for (int l=i-1 ;l>=0 ;l--)leftMax=Math.max(leftMax,height[l]); for (int r=i+1 ;r<height.length;r++)rightMax=Math.max(rightMax,height[r]); int min = Math.min(leftMax,rightMax); int area = Math.max(0 ,min - height[i]); ans+=area; } return ans; } public int trap (int [] height) { int [] leftMax = new int [height.length]; leftMax[0 ] = height[0 ]; for (int i = 1 ; i < height.length; i++) leftMax[i] = Math.max(leftMax[i-1 ],height[i]); int [] rightMax = new int [height.length]; rightMax[rightMax.length-1 ] = height[height.length-1 ]; for (int i = rightMax.length-2 ; i >= 0 ; i--)rightMax[i] = Math.max(rightMax[i+1 ],height[i]); int ans = 0 ; for (int i = 0 ; i < height.length; i++)ans+=Math.min(leftMax[i],rightMax[i])-height[i]; return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public void nextPermutation (int [] nums) { for (int i = nums.length-1 ; i > 0 ; i--) { if (nums[i]>nums[i-1 ]){ int index = i; for (int j = i; j < nums.length ; j++) { if (nums[j]>nums[i-1 ]&&nums[j]-nums[i-1 ]<nums[index]-nums[i-1 ])index=j; } int temp = nums[i-1 ]; nums[i-1 ] = nums[index]; nums[index] = temp; Arrays.sort(nums,i,nums.length); return ; } } Arrays.sort(nums); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { public int firstMissingPositive (int [] nums) { int n = nums.length; for (int i = 0 ; i < n; ++i) { if (nums[i] <= 0 ) { nums[i] = n + 1 ; } } for (int i = 0 ; i < n; ++i) { int num = Math.abs(nums[i]); if (num <= n) { nums[num - 1 ] = -Math.abs(nums[num - 1 ]); } } for (int i = 0 ; i < n; ++i) { if (nums[i] > 0 ) { return i + 1 ; } } return n + 1 ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { public int findMinDifference (List<String> timePoints) { int len = timePoints.size(); if (len > 1440 ) return 0 ; int [] times = new int [timePoints.size()]; for (int i=0 ;i<len;i++){ String t1 = timePoints.get(i); int t1_h = Integer.valueOf(t1.substring(0 ,2 )); int t1_m = Integer.valueOf(t1.substring(3 ,5 )); times[i] = t1_h * 60 + t1_m; } Arrays.sort(times); int min = times[0 ]+1440 -times[len-1 ]; for (int i=1 ;i<len;i++){ min = Math.min(min,times[i]-times[i-1 ]); } return min; } public int findMinDifference0 (List<String> timePoints) { int n = timePoints.size(); if (n > 1440 ) return 0 ; Collections.sort(timePoints); int ans = Integer.MAX_VALUE; int t0Minutes = getMinutes(timePoints.get(0 )); int preMinutes = t0Minutes; for (int i = 1 ; i < n; ++i) { int minutes = getMinutes(timePoints.get(i)); ans = Math.min(ans, minutes - preMinutes); preMinutes = minutes; } ans = Math.min(ans, t0Minutes + 1440 - preMinutes); return ans; } public int getMinutes (String t) { return ((t.charAt(0 ) - '0' ) * 10 + (t.charAt(1 ) - '0' )) * 60 + (t.charAt(3 ) - '0' ) * 10 + (t.charAt(4 ) - '0' ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 / / 二分查找 public boolean searchMatrix(int [][] matrix, int target) { int m = matrix.length; int n = matrix[0 ].length; int left = 0 ,right = (m* n)-1 ; int pivotIdx = 0 , pivotElement = 0 ; while(left <= right ){ pivotIdx = (left + right )/ 2 ; pivotElement = matrix[pivotIdx/ n][pivotIdx% n]; if(target= = pivotElement)return true ; else { if(target< pivotElement)right = pivotIdx-1 ; else left = pivotIdx + 1 ; } } return false ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 class Solution { / / 思路: / / 1. 若左下角元素等于目标,则找到 / / 2. 若左下角元素大于目标,则目标不可能存在于当前矩阵的最后一行,问题规模可以减小为在去掉最后一行的子矩阵中寻找目标 / / 3. 若左下角元素小于目标,则目标不可能存在于当前矩阵的第一列,问题规模可以减小为在去掉第一列的子矩阵中寻找目标 / / 4. 若最后矩阵减小为空,则说明不存在 public boolean searchMatrix(int [][] matrix, int target) { int x= matrix.length-1 ,y= 0 ; while(x>= 0 && y< matrix[0 ].length){ if(matrix[x][y]= = target) return true ; if(matrix[x][y]> target) x else y+ + ; } return false ; } } class Solution { / / [1 ,4 ,7 ,11 ,15 ], / / [2 ,5 ,8 ,12 ,19 ], / / [3 ,6 ,9 ,16 ,22 ], / / [10 ,13 ,14 ,17 ,24 ], / / [18 ,21 ,23 ,26 ,30 ]] / / 根据定义可知同一行左边小于右边,同一列上边小于下边。 / / 1. 右上角大于同一行左边的所有数,小于同一列下边的所有数,其位于中间可以定位target在哪一边, / / 如果右上角大于target,因为该列从上到下递增(下面所有的数都大于target),所以target必不肯能在该列,排除该列,y / / 如果右上角小于target,因为该行从左到右递增(左边所有的数都小于target),所以target必不肯能在该行,排除该行,x+ + 向下一行继续查找 / / (左下角同理) / / 2. 左上角和右下角分别都小于和大于所有的数,无法确定其区间 / / 方法1 从右上角开始查询: / / 从二维数组的右上角开始查找。如果当前元素等于目标值,则返回 true 。 / / 如果当前元素大于目标值,则移到左边一列。 / / 如果当前元素小于目标值,则移到下边一行。 / / 方法2 从左下角开始查询: / / 从二维数组的左下角开始查找。如果当前元素等于目标值,则返回 true 。 / / 如果当前元素大于目标值,则移到上边一行。 / / 如果当前元素小于目标值,则移到右边一列。 public boolean findNumberIn2DArray(int [][] matrix, int target) { / / 方法1 if(matrix= = null || matrix.length= = 0 || matrix[0 ].length= = 0 )return false ; int m = matrix.length; int n = matrix[0 ].length; int x = 0 ,y = n - 1 ; while (x< m&& y>= 0 ){ if (matrix[x][y]= = target)return true ; else if(matrix[x][y]> target)y else x+ + ; } return false ; / / 方法2 if(matrix= = null || matrix.length= = 0 || matrix[0 ].length= = 0 )return false ; int m = matrix.length; int n = matrix[0 ].length; int x = m-1 ,y = 0 ; while (y< n&& x>= 0 ){ if (matrix[x][y]= = target)return true ; else if(matrix[x][y]> target)x else y+ + ; } return false ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { / / 思路:bfs private int max; private int area; public int maxAreaOfIsland(int [][] grid) { int m = grid.length; int n = grid[0 ].length; for (int i= 0 ;i< m;i+ + ){ for (int j= 0 ;j< n;j+ + ){ if(grid[i][j]= = 1 ){ area= 0 ; bfs(grid,i,j); max= Math.max (max,area); } } } return max; } public void bfs(int [][] grid,int x,int y){ area+ = 1 ; grid[x][y]= 0 ; / / 上 if(x> 0 && grid[x-1 ][y]= = 1 )bfs(grid,x-1 ,y); / / 下 if(x< grid.length-1 && grid[x+ 1 ][y]= = 1 )bfs(grid,x+ 1 ,y); / / 左 if(y> 0 && grid[x][y-1 ]= = 1 )bfs(grid,x,y-1 ); / / 右 if(y< grid[0 ].length-1 && grid[x][y+ 1 ]= = 1 )bfs(grid,x,y+ 1 ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { / / 思路:排序。按照每个数位比较,优先使用位大的 public String largestNumber(int [] nums) { StringBuilder sb = new StringBuilder(); String[] arr = new String[nums.length]; for (int i= 0 ;i< arr.length;i+ + )arr[i]= String.valueOf(nums[i]); Arrays.sort(arr, new Comparator< String> () { @Override public int compare(String o1, String o2) { / / 继承此方法的时候,要自定义比较器,conpareTo方法返回值为1 (升序),0 ,-1 (降序)。返回正值 交换;负值不交换 return (o2 + o1).compareTo((o1 + o2)); } }); for (String s:arr)sb.append(s); String ans = sb.toString(); if(ans.charAt(0 )= = '0' )ans = "0"; return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution { public int [] findDiagonalOrder(int [][] mat) { int m = mat.length; int n = mat[0 ].length; int t = m+ n-1 ; int [] ans = new int [m* n]; for (int i = 0 ,x = 0 ,y = 0 ,index= 0 ; i < t; i+ + ) { / / 遍历一轮 while (x>= 0 && x< m&& y>= 0 && y< n){ if (i% 2 = = 0 ) {/ / 上 ans[index+ + ]= mat[x][y]; x y+ + ; }else {/ / 下 ans[index+ + ]= mat[x][y]; x+ + ; y } } if (i% 2 = = 0 ){/ / 上 if (x< 0 && y= = n){ x+ = 2 ; y } else if (x< 0 )x+ + ;/ / 归位 else if (y= = n){ x+ = 2 ; y } }else { if (y< 0 && x= = m){ y+ = 2 ; x } else if (y< 0 )y+ + ;/ / 归位 else if (x= = m){ y+ = 2 ; x } } } return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Solution { / / 双指针p1指向 / / [0 ,1 ,0 ,3 ,12 ] / / [1 ,1 ,0 ,3 ,12 ] / / [1 ,3 ,0 ,3 ,12 ] / / [1 ,3 ,12 ,3 ,12 ] / / [1 ,3 ,12 ,0 ,0 ] public void moveZeroes(int [] nums) { int p1 = 0 ,p2 = 0 ; while(p2< nums.length){ if(nums[p2]!= 0 ){ nums[p1+ + ] = nums[p2]; } p2+ + ; } / / p1后面全部置0 while(p1< nums.length)nums[p1+ + ]= 0 ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution { / / 双指针,首尾遍历(首寻找偶数,尾寻找奇数,交换位置) public int [] exchange(int [] nums) { int left = 0 ,right = nums.length-1 ; while(left < right ){ while(left < right && (nums[left ]& 1 )= = 1 )left + + ; while(right > 0 && (nums[right ]& 1 )= = 0 )right if(left < right ){ int l = nums[left ]; nums[left ] = nums[right ]; nums[right ] = l; } left + + ; right } return nums; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 / / properties[i] = [attack, defense]/ / 思路:排序+ 比较 public int numberOfWeakCharacters0(int [][] properties) { Arrays.sort(properties, (o1, o2) - > { return o1[0 ] = = o2[0 ] ? (o1[1 ] - o2[1 ]) : (o2[0 ] - o1[0 ]);/ / properties[attack, defense]对attack降序defense升序排序 }); int maxDef = 0 ; int ans = 0 ; / / 此时properties已经排序好,只需要比较每个properties的defense是否小于maxDef,小于更新ans,不小于则更新maxDef for (int [] p : properties) { if (p[1 ] < maxDef) { ans+ + ; } else { maxDef = p[1 ]; } } return ans; }/ / 单调栈 public int numberOfWeakCharacters(int [][] properties) { Arrays.sort(properties, (o1, o2) - > { return o1[0 ] = = o2[0 ] ? (o2[1 ] - o1[1 ]) : (o1[0 ] - o2[0 ]);/ / properties[attack, defense]对attack升序defense降序排序 }); int ans = 0 ; Deque< Integer > st = new ArrayDeque< Integer > (); / / 此时properties中的attack从小到大,attack相等defense小的在后面 / / 遍历数组properties,栈顶小于当前properties[i]将其弹栈,否则压栈 for (int [] p : properties) { while (! st.isEmpty() && st.peek() < p[1 ]) { st.pop(); ans+ + ; } st.push(p[1 ]); } return ans; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution { / / 注意题目要求的是连续的子数组,所以可以通过暴力直接滑动求 public int subarraySum0(int [] nums, int k) { int n = nums.length; int ans = 0 ; for (int start = 0 ;start < n;start + + ){ int sum = 0 ; for (int end = start ;end >= 0 ;end sum+ = nums[end ]; if(sum= = k)ans+ + ; } } return ans; } / / 前缀和优化,map存储从0 - i的数和,当我们需要求连续数组和为k的值时,只需要判断num[i]- k的前缀和是否存在即可 / / 以map来存储前缀和为键,次数为值 public int subarraySum(int [] nums, int k) { int count = 0 , pre = 0 ; HashMap < Integer , Integer > mp = new HashMap < > (); mp.put(0 , 1 ); for (int i = 0 ; i < nums.length; i+ + ) { pre + = nums[i]; if (mp.containsKey(pre - k)) {/ / 判断是否存在前缀和为pre- k的值 count + = mp.get(pre - k); } mp.put(pre, mp.getOrDefault(pre, 0 ) + 1 ); } return count; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Solution { private int [] nums; private int [] origin; public Solution(int [] nums) { this.nums = nums; int [] origin = new int [nums.length]; System.arraycopy(nums,0 ,origin,0 ,nums.length); this.origin = origin; } public int [] reset() { return origin; } / / bf public int [] shuffle1() { List< Integer > list = new ArrayList<> (); int [] shuffle = new int [nums.length]; for (int n:origin)list.add(n); Random random = new Random(); / / 每次在list里随机获取一个数来填充shuffle for (int i= 0 ;i< nums.length;i+ + ){ int r = random.nextInt(list.size()); shuffle[i] = list.remove(r); } return shuffle; } / / Fisher- Yates 洗牌算法 / / 将当前nums[i]元素与nums(i,n)随机元素交换位置,减少了创建list的开销 public int [] shuffle() { Random random = new Random(); for (int i= 0 ;i< nums.length;i+ + ){ int index = i+ random.nextInt(nums.length- i); int tmp = nums[i]; nums[i] = nums[index]; nums[index] = tmp; } return nums; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution { / / set public int [] intersectionSet(int [] nums1, int [] nums2) { List< Integer > list = new ArrayList<> (); Set < Integer > set1 = new HashSet<> (); Set < Integer > set2 = new HashSet<> (); for (int n:nums1)set1.add(n); for (int n:nums2)set2.add(n); for (int n:set1){ if (set2.contains(n)){ list.add(n); } } int [] ret = new int [list.size()]; for (int i = 0 ; i < list.size(); i+ + ) ret[i] = list.get(i); return ret; } / / 排序+ 双指针 / / [4 ,5 ,9 ] / / [4 ,4 ,8 ,9 ,9 ] public int [] intersection (int [] nums1, int [] nums2) { Arrays.sort(nums1); Arrays.sort(nums2); int m = nums1.length; int n = nums2.length; int [] intersection = new int [m+ n]; int index = 0 ,index1 = 0 ,index2 = 0 ; while(index1< m&& index2< n){ int n1 = nums1[index1]; int n2 = nums2[index2]; if(n1= = n2){ / / 判断是否重复 if(index= = 0 || n1!= intersection [index-1 ])intersection [index+ + ]= n1; index1+ + ; index2+ + ; }else if(n1< n2){ index1+ + ; }else { index2+ + ; } } return Arrays.copyOfRange(intersection ,0 ,index); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public int findMinFibonacciNumbers(int k) { / / 求出斐波拉契数列 List< Integer > f = new ArrayList< Integer > (); f.add(1 ); int a = 1 , b = 1 ; while (a + b <= k) { int c = a + b; f.add(c); a = b; b = c; } / / 由题目已知,数据保证对于给定的 k ,一定能找到可行解,所以可以从后往前查找 int ans = 0 ; for (int i = f.size() - 1 ; i >= 0 && k > 0 ; i int num = f.get(i); if (k >= num) { k - = num; ans+ + ; } } return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Solution { / / [1 ,2 ,3 ,4 ], / / [5 ,6 ,7 ,8 ], / / [9 ,10 ,11 ,12 ] / / 思路:四个变量控制边界 public int [] spiralOrder(int [][] matrix) { int m = matrix.length; if(matrix= = null || m= = 0 )return new int [0 ]; int n = matrix[0 ].length; if(n= = 0 )return new int [0 ]; int retLen = m * n; int [] ret = new int [retLen]; int index = 0 ; int left = 0 ,right = n - 1 ,up = 0 ,down = m - 1 ; while(left <= right && up<= down){ for (int i= left ;i<= right ;i+ + )ret[index+ + ]= matrix[up][i];/ / 右边 for (int i= up+ 1 ;i<= down;i+ + )ret[index+ + ]= matrix[i][right ];/ / 下 if(up< down&& left < right ){ for (int i= right -1 ;i> left ;i for (int i= down;i> up;i } up+ + ; right down left + + ; } return ret; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { / / 原地hash:对数组每个元素所映射的下标都加N,在遍历数组进行判断是否大于N,对N取模得出原来的数 public List< Integer > findDuplicates(int [] nums) { List< Integer > ret = new ArrayList<> (); int N = 1000000 ; for (int i= 0 ;i< nums.length;i+ + ){ if(nums[nums[i]% N-1 ]< N){ nums[nums[i]% N-1 ]+ = N; }else { ret.add(nums[i]% N); } } return ret; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution { / / 条件:1. 0 <= i < len(arr)/ 2 2. arr[2 * i + 1 ] = 2 * arr[2 * i] / / 考查:数组中是否存在n/ 2 对数,每对元素中一个数是另一个数的两倍,可能涉及的数据结构:排序、哈希表 / / 思路:map统计每个数出现的频率,对出现的数进行绝对值排序(因为要优先使用小的数来匹配,由于2 * 负数= 更小的负数,更小的负数排序后会在后面),遍历查看是否都匹配 / / 边界:和0 匹配的值只能是0 public boolean canReorderDoubled(int [] arr) { int n = arr.length; Map< Integer ,Integer > map = new HashMap<> (300 ); for (int num:arr){ map.put(num,map.getOrDefault(num,0 )+ 1 ); } if(map.getOrDefault(0 ,0 )% 2 != 0 )return false ; List< Integer > values = new ArrayList<> (map.size()); for (Integer key:map.keySet())values.add(key); / / 排序前:7 ,2 ,-2 ,-3 ,5 ,6 / / 排序后:2 ,-2 ,-3 ,5 ,6 ,7 Collections.sort(values ,(x,y)- > Math.abs (x)- Math.abs (y)); for (int num:values ) { int key = 2 * num; int c2 = map.getOrDefault(key,0 ); int c1 = map.get(num); if(c2< c1)return false ; map.put(key,c2- c1); } return true ; } }
相关资料