数组的经典算法题

移动数组

  1. //给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
  2. //
  3. // 示例:
  4. //
  5. // 输入: [0,1,0,3,12]
  6. //输出: [1,3,12,0,0]
  7. //
  8. // 说明:
  9. //
  10. //
  11. // 必须在原数组上操作,不能拷贝额外的数组。
  12. // 尽量减少操作次数。
  13. //
  14. // Related Topics 数组 双指针
  15. //leetcode submit region begin(Prohibit modification and deletion)
  16. class Solution {
  17. public void moveZeroes(int[] nums) {
  18. //1 读懂题目要求:
  19. // 将数组中 0 移动到数组的末尾,同时保持非零元素的相对顺序
  20. // 必须在原数组上操作,不能拷贝额外的数组
  21. // 尽量减少操作次数
  22. //2 解题思路:
  23. // 解法1: loop数组非0的当前loop count+1 一次从0开始替换不为0的元素,然后在loop 从count开始剩余的元素都是0
  24. // int count = 0;
  25. // for (int i = 0; i < nums.length; i++) {
  26. // if (nums[i] != 0) {
  27. // nums[count++] = nums[i];
  28. // }
  29. // }
  30. // for (int i = count; i <nums.length ; i++) {
  31. // nums[i] = 0;
  32. // }
  33. // 解法2: 上述使用了两个循环还可以在进行优化:通过类似的两个指针快慢指针,进行替换操作
  34. for (int i = 0,count = 0; i < nums.length; i++) {
  35. if (nums[i] != 0){
  36. //快慢指针进行元素替换操作
  37. // int temp = nums[i];
  38. // nums[i] = nums[count];
  39. // nums[count] = temp;
  40. // count++;
  41. //以上替换操作还可以在优化 可以将temp优化掉
  42. if (count != i){
  43. nums[count] = nums[i];
  44. nums[i] = 0;
  45. }
  46. count++;
  47. }
  48. }
  49. }
  50. }
  51. //leetcode submit region end(Prohibit modification and deletion)

合并排序数组

  1. //给定两个排序后的数组 A 和 B,其中 A 的末端有足够的缓冲空间容纳 B。 编写一个方法,将 B 合并入 A 并排序。
  2. //
  3. // 初始化 A 和 B 的元素数量分别为 m 和 n。
  4. //
  5. // 示例:
  6. //
  7. // 输入:
  8. //A = [1,2,3,0,0,0], m = 3
  9. //B = [2,5,6], n = 3
  10. //1 2 3 2 5 6
  11. //输出: [1,2,2,3,5,6]
  12. // Related Topics 数组 双指针
  13. import java.util.Arrays;
  14. //leetcode submit region begin(Prohibit modification and deletion)
  15. class Solution {
  16. public void merge(int[] A, int m, int[] B, int n) {
  17. // solutionOne(A,m,B,n);
  18. }
  19. /**
  20. * 逆向双指针解法:双指针从m n的位置来时逆向查找 并添加到数组的尾部,注意
  21. * 已经排好序的数组哪个大就会在最后,原地修改数组A 而不用在开一个额外的数组空间
  22. *
  23. * @param A
  24. * @param m
  25. * @param B
  26. * @param n
  27. */
  28. public void solutionS(int[] A, int m, int[] B, int n) {
  29. int pa = m - 1;
  30. int pb = n - 1;
  31. int t = m + n - 1;
  32. int cur = 0;
  33. while (pa >= 0 || pb >= 0) {
  34. if (pa == -1){
  35. cur = B[pb--];
  36. }else if (pb == -1){
  37. cur = A[pa--];
  38. }else if (A[pa] > B[pb]){
  39. cur = A[pa--];
  40. } else {
  41. cur = B[pb--];
  42. }
  43. A[t--] = cur;
  44. }
  45. }
  46. /**
  47. * 双指针解法:注意题目描述的是A B 已经被排序利用这个性质来解答,注意双指针解法
  48. * 在数组中必须是排好序的数组,既然A B 已经排好序了,那么一个指针指向A 的0下标pa=0, 一个
  49. * 指针指向B的0 下标pb=0,判断A[pa] B[pb]的大小 小的那个放到一个新的数组中,如果pa==m||pb==n 则循环终止
  50. * @param A
  51. * @param m
  52. * @param B
  53. * @param n
  54. */
  55. public void solutionTwo(int[] A, int m, int[] B, int n){
  56. int pa=0,pb=0;
  57. int[] result = new int[m+n];
  58. int count = 0;
  59. int cur = 0;
  60. while (pa < m || pb < n){
  61. if (pa == m){
  62. cur = B[pb++];
  63. }else if (pb == n){
  64. cur = A[pa++];
  65. }else if (A[pa] < B[pb]){
  66. cur = A[pa++];
  67. }else{
  68. cur = B[pb++];
  69. }
  70. result[count++] = cur;
  71. }
  72. for (int i = 0; i < result.length; i++) {
  73. A[i] = result[i];
  74. }
  75. }
  76. /**
  77. * 暴力破解法:
  78. * 思路:既然题目要求要合并到A中,首先将B的数据合并到A中,然后在对A进行排序
  79. * @param A
  80. * @param m
  81. * @param B
  82. * @param n
  83. */
  84. public void solutionOne(int[] A, int m, int[] B, int n){
  85. int num = m + n;
  86. //1 将B的数据添加到A中 1 2 3 2 5 6 直接从m开始向A中添加数据
  87. //边界
  88. //[0,0]
  89. //0
  90. //[1]
  91. //1
  92. //错误用例:
  93. //[4,0,0,0,0,0]
  94. //1
  95. //[1,2,3,5,6]
  96. //5
  97. for (int i = 0; i < n; i++) {
  98. A[m + i] = B[i];
  99. }
  100. //2 排序A中的数据 通过快慢双指针进行 1 2 3 2 5 6
  101. for (int i = 0; i < num - 1; i++) {
  102. for (int j = i + 1; j < num; j++) {
  103. if (A[i] > A[j]) {
  104. int temp = A[j];
  105. A[j] = A[i];
  106. A[i] = temp;
  107. }
  108. }
  109. }
  110. }
  111. }
  112. //leetcode submit region end(Prohibit modification and deletion)

两数之和

  1. //给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
  2. //
  3. // 你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
  4. //
  5. // 示例:
  6. //
  7. // 给定 nums = [2, 7, 11, 15], target = 9
  8. //
  9. //因为 nums[0] + nums[1] = 2 + 7 = 9
  10. //所以返回 [0, 1]
  11. //
  12. // Related Topics 数组 哈希表
  13. //leetcode submit region begin(Prohibit modification and deletion)
  14. class Solution {
  15. public int[] twoSum(int[] nums, int target) {
  16. Map<Integer,Integer> map = new HashMap<>();//记录所有数组值和下标
  17. for(int i=0;i<nums.length;i++){
  18. int result = target - nums[i];
  19. if(map.containsKey(result) && map.get(result) != i){
  20. return new int[]{map.get(result),i};
  21. }else{
  22. map.put(nums[i],i);
  23. }
  24. }
  25. return new int[]{};
  26. }
  27. }
  28. //leetcode submit region end(Prohibit modification and deletion)

三数之和

  1. //给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复
  2. //的三元组。
  3. //
  4. // 注意:答案中不可以包含重复的三元组。
  5. //
  6. //
  7. //
  8. // 示例:
  9. //
  10. // 给定数组 nums = [-1, 0, 1, 2, -1, -4],
  11. //
  12. //满足要求的三元组集合为:
  13. //[
  14. // [-1, 0, 1],
  15. // [-1, -1, 2]
  16. //]
  17. //
  18. // Related Topics 数组 双指针
  19. import java.util.ArrayList;
  20. import java.util.Arrays;
  21. import java.util.List;
  22. //leetcode submit region begin(Prohibit modification and deletion)
  23. class Solution {
  24. public List<List<Integer>> threeSum(int[] nums) {
  25. List<List<Integer>> lists = new ArrayList<>();
  26. if(nums == null || nums.length < 3) return lists;
  27. // 假设输入:[-1, 0, 1, 2, -1, -4]
  28. //先对数组进行排序 数组一般的解法使用双指针解法 要使用双指针解法就必须是排好序的数组
  29. Arrays.sort(nums);//[-4,-1,-1,0,1,2]
  30. //数组最大的下标
  31. int len = nums.length - 1;
  32. //判断边界值
  33. if (nums[0] > 0 || nums[len] < 0) {//如果最小值大于0 那么不可能有相加等于0的,如果最大值<0 那么整个数组的值都是小于0 那么也不可能得到结果
  34. return lists;
  35. }
  36. //[-4,-1,-1,0,1,2]
  37. // L R
  38. // i = L+1
  39. for (int i = 0; i < nums.length - 2; i++) {
  40. //判断 num[i] 和 num[i+1]是否重复
  41. if (i > 0 && nums[i] == nums[i - 1]) continue;
  42. int L = i + 1;
  43. int R = nums.length - 1;
  44. while (L < R) {
  45. int result = nums[L] + nums[R] + nums[i];
  46. if (result < 0) {
  47. //如果得到的结果小于0则说明L要完右移动 增大值 同时要判断L是否重复
  48. L++;
  49. } else if (result > 0) {
  50. //如果得到的结果大于0则说明R要往左移动 减小值 同时要判断R是否重复
  51. R--;
  52. } else {
  53. lists.add(Arrays.asList(nums[i], nums[L], nums[R]));
  54. //==0 说明得到结果了 同时还得去重
  55. while (L < R && nums[L] == nums[L + 1]) L++;
  56. L++;
  57. while (L < R && nums[R] == nums[R - 1]) R--;
  58. R--;
  59. }
  60. }
  61. }
  62. return lists;
  63. }
  64. }
  65. //leetcode submit region end(Prohibit modification and deletion)

数组算法解题思路

  • 排序数组
  • 双指针
  • 哈希表