专题【双指针】【学习题】刷题日记

题目列表

11. 盛最多水的容器
42. 接雨水
15. 三数之和
16. 最接近的三数之和
18. 四数之和
26. 删除有序数组中的重复项
27. 移除元素
75. 颜色分类
167. 两数之和 II - 输入有序数组
283. 移动零
287. 寻找重复数
350. 两个数组的交集 II
977. 有序数组的平方


2024.04.06

11. 盛最多水的容器

题目

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明: 你不能倾斜容器。

示例 1:
在这里插入图片描述

输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

提示:

  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104

思路

  1. 从图可知,接水量=Math.min(left, right) * (rightIndex - leftIndex)
  2. 可以用双指针
  3. 因为要找最大值,而且双指针相向而行(宽度在变小),只有最小高度变大才可能有最大值,所以移动高度相对较低的一端

答案

class Solution {
    public int maxArea(int[] height) {
        int length = height.length;
        if (length < 2) {
            return 0;
        }
        int left = 0;
        int right = length - 1;

        int leftH = height[left];
        int rightH = height[right];
        
        int result = 0;
        while (left < right) {
            int h = Math.min(leftH, rightH);
            result = Math.max(result, h * (right - left));
            if (leftH == h) {
                left++;
                // 此处快速收敛一下,因为leftH >= height[left],就不可能更大
                while (left < right && leftH >= height[left]) {
                    left++;
                }
                leftH = height[left];
                
            } else {
                right--;
                // 同left处
                while (left < right && rightH >= height[right]) {
                    right--;
                }
                rightH = height[right];
            }
        }
        return result;
    }
}

42. 接雨水

题目

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:
在这里插入图片描述

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

  • n == height.length
  • 1 <= n <= 2 * 104
  • 0 <= height[i] <= 105

思路

和上一题的区别是,上一题认为每个位置的高度都是0,本题是有一个基础高度
所以不能简单的用high * length,要逐个计算高度
整体思路和上一题类似,区别是每个格子能盛水的量是,Math.min(左max,右max)

答案

class Solution {
    public int trap(int[] height) {
        int length = height.length;
        if (length < 2) {
            return 0;
        }
        int left = 0;
        int right = length - 1;

        int leftHMax = height[left];
        int rightHMax = height[right];
        
        int result = 0;
        // 因为计算高度在判断后进行。判断后会进行一次位移,left和right会重合,这里不需要left <= right
        while (left < right) {
            int minMax = Math.min(leftHMax, rightHMax);
            if (minMax == leftHMax) {
                left++;
                if (height[left] < minMax) {
                    result += minMax - height[left];
                } else {
                    leftHMax = height[left];
                }
            } else {
                right--;
                if (height[right] < minMax) {
                    result += minMax - height[right];
                } else {
                    rightHMax = height[right];
                }
            }
        }
        return result;
    }
}

15. 三数之和

题目

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。

注意: 答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

思路

  1. 循环每一个数,然后变为newTarget = target - nums[i]的两数之和
  2. 排序之后,循环每一个数,然后双指针。
  3. newTarget = target - nums[i]。left + right = newTarget。
  4. 因为排序,left向右则和变大,right向左则和变小
  5. 综上,用双指针

答案

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int length = nums.length;
        sorted(nums, 0, length - 1);
        List<List<Integer>> result = new ArrayList<>();
        for (int i = 0; i < length - 1; i++) {
            if (nums[i] > 0) {
                return result;
            }
            // 去除重复元素
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            int target = -nums[i];
            int left = i + 1;
            int right = length - 1;
            while (left < right) {
                int sum = nums[left] + nums[right];
                if (sum == target) {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    // 去除重复元素,这里用left和left+1对比,而不是用left和left-1对比,是为了后续移动left统一操作
                    while (left < right && nums[left] == nums[left+1]) {
                        left++;
                    }
                    // 去除重复元素
                    while (left < right && nums[right] == nums[right - 1]) {
                        right--;
                    }
                    left++;
                    right--;
                } else if (sum < target) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        return result;
    }
	// 顺便练习下,有重复元素的快排(颜色分类用到了)
    public void sorted(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }
		// min指向小于element元素的下一个值(不包含)[left, mid)是小于element的
		// mid指向当前遍历元素[min, mid)是和element相等的值
		// max是指向第一个比element大的元素的左边的元素,(max, right] 比element大
		// [mid, max]是未遍历元素
        int min = left, mid = min + 1, max = right;
        int element = nums[min];
        while (mid <= max) {
            int current = nums[mid];
            if (element == current) {
                mid++;
            } else if (element < current) {
                swap(nums, mid, max--);
            } else {
                swap(nums, min++, mid++);
            }
        }
        //因为min和max都是开区间,所以,这里做一个位移
        sorted(nums, left, min - 1);
        sorted(nums, max + 1, right);
    }

    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

2024.04.07

16. 最接近的三数之和

题目

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。

示例 1:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

示例 2:

输入:nums = [0,0,0], target = 1
输出:0

提示:

  • 3 <= nums.length <= 1000
  • -1000 <= nums[i] <= 1000
  • -104 <= target <= 104

思路

同上三数之和,可以作为练习题

答案

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        int length = nums.length;
        int result = 0;
        sorted(nums, 0, length - 1);

        int min = Integer.MAX_VALUE;
        for (int i = 0; i < length; i++) {
            int nums1 = nums[i];
            int left = i + 1;
            int right = length - 1;
            while (left < right) {
                int sum = nums1 + nums[left] + nums[right];
                // 判断差值
                if (Math.abs(sum - target) < min) {
                    min = Math.abs(sum - target);
                    result = sum;
                }
                // 找到直接截断
                if (sum ==  target) {
                    return sum;
                } else if (sum < target) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        return result;
    }
    
    private void sorted(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }
        int element = nums[left];
        int min = left, mid = min + 1, max = right;
        while (mid <= max) {
            int current = nums[mid];
            if (current == element) {
                mid++;
            } else if (current < element) {
                swap(nums, min++, mid++);
            } else {
                swap(nums, mid, max--);
            }
        }
        sorted(nums, left, min - 1);
        sorted(nums, max + 1, right);
    }

    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

18. 四数之和

题目

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • a、b、c 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

示例 1:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2:

输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

提示:

  • 1 <= nums.length <= 200
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109

思路

和三数之和类似
区别是

  1. 需要两次循环
  2. length条件不一样
  3. nums[i]的条件不一样,可能相加之后溢出

答案

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> result = new ArrayList<>();
        int length = nums.length;
        if (length < 4) {
            return result;
        }
        sorted(nums, 0, length - 1);

        for (int i = 0; i < length - 3; i++) {
            long first = nums[i];
            // 快速截断,已经超过目标值了
            if (first + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
                break;
            }
            // 快速截断,不可能达成
            if (first + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
                continue;
            }
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            for (int j = i + 1; j < length - 2; j++) {
           		// 同上
                if (first + nums[j] + nums[j + 1] + nums[j + 2] > target) {
                    break;
                }
                // 同上
                if (first + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
                    continue;
                }
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }
                int second = nums[j];
                int left = j + 1;
                int right = length - 1;
                while (left < right) {
                    long sum = first + second + nums[left] + nums[right];
                    if (sum == target) {
                        result.add(Arrays.asList((int) first, second, nums[left], nums[right]));
                        while (left < right && nums[left] == nums[left + 1]) {
                            left++;
                        }
                        while (left < right && nums[right] == nums[right - 1]) {
                            right--;
                        }
                        left++;
                        right--;
                    } else if (sum < target) {
                        left++;
                    } else {
                        right--;
                    }
                }
            }
        }
        return result;
    }

    private void sorted(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }
        int element = nums[left];
        int min = left, mid = min + 1, max = right;

        while (mid <= max) {
            int current = nums[mid];
            if (current == element) {
                mid++;
            } else if (current < element) {
                swap(nums, min++, mid++);
            } else {
                swap(nums, mid, max--);
            }
        }
        sorted(nums, left, min - 1);
        sorted(nums, max + 1, right);

    }

    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

26. 删除有序数组中的重复项

题目

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = […]; // 输入数组
int[] expectedNums = […]; // 长度正确的期望答案
int k = removeDuplicates(nums); // 调用
assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过。

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示:

  • 1 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • nums 已按 非严格递增 排列

思路

  1. 一个size记录新的大小
  2. 如果下一个元素和当前元素相等,size就不动
  3. 否则size+1,并把当前位置的元素复制过来

答案

class Solution {
    public int removeDuplicates(int[] nums) {
        int size = 0;
        // 看提示,可以确认大小范围
        int last = -100000;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == last) {
                continue;
            } else {
                nums[size++] = nums[i];
                last = nums[i];
            }
        }
        return size;
    }
}

27. 移除元素

题目

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。

示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,3,0,4]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

提示:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100

思路

和上一题相同。区别是,size变更的条件
上一题是last和当前不相等
这个一题是val和当前不相等

答案

class Solution {
    public int removeElement(int[] nums, int val) {
        int size = 0;
        for (int i = 0; i < nums.length; i++) {
            int current = nums[i];
            if (current == val) {
                continue;
            } else {
                nums[size++] = nums[i];
            }
        }
        return size;
    }
}

75. 颜色分类

题目

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库内置的 sort 函数的情况下解决这个问题。

示例 1:

输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]

示例 2:

输入:nums = [2,0,1]
输出:[0,1,2]

提示:

  • n == nums.length
  • 1 <= n <= 300
  • nums[i] 为 0、1 或 2

进阶:

  • 你能想出一个仅使用常数空间的一趟扫描算法吗?

思路

重复元素排序

元素

class Solution {
    public void sortColors(int[] nums) {
        sorted(nums, 0, nums.length - 1);
    }
    private void sorted(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }
        int element = nums[left];
        int min = left, mid = min + 1, max = right;
        while (mid <= max) {
            int current = nums[mid];
            if (element == current) {
                mid++;
            } else if (current < element) {
                swap(nums, min++, mid++);
            } else {
                swap(nums, mid, max--);
            }
        }
        sorted(nums, left, min - 1);
        sorted(nums, max + 1, right);
    }

    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

167. 两数之和 II - 输入有序数组

题目

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

示例 2:

输入:numbers = [2,3,4], target = 6
输出:[1,3]
解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。

示例 3:

输入:numbers = [-1,0], target = -1
输出:[1,2]
解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

提示:

  • 2 <= numbers.length <= 3 * 104
  • -1000 <= numbers[i] <= 1000
  • numbers 按 非递减顺序 排列
  • -1000 <= target <= 1000
  • 仅存在一个有效答案

思路

三数之和的简单版本

答案

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int l = 0, r = numbers.length - 1;
        while (l < r) {
            int current = numbers[l] + numbers[r];
            if (current > target) {
                r--;
            } else if (current < target) {
                l++;
            } else {
            	// 题目要求从1开始
                return new int[] { l + 1, r + 1 };
            }
        }
        return new int[2];
    }
}

2024.04.09

283. 移动零

题目

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]
输出: [0]

提示:

  • 1 <= nums.length <= 104
  • -231 <= nums[i] <= 231 - 1

进阶: 你能尽量减少完成的操作次数吗?

思路

两个指针,1个指向0,一个指向当前遍历位置,然后交换
说明
为什么相对顺序不会乱
如果没有0,则两个指针一直重合
如果有0,则一直在把0往后换
可以理解成,指向0的指针(zeroIndex)和指向当前的指针(currentIndex)
[0, zeroIndex) 为0,[zeroIndex, currentIndex]为非0,(currentIndex, 最大】

答案

class Solution {
    public void moveZeroes(int[] nums) {

        int zeroIndex = 0, current = 0;
        int length = nums.length;
      
        while (current < length) {
            if (nums[current] != 0) {
                int temp = nums[current];
                nums[current] = nums[zeroIndex];
                nums[zeroIndex] = temp;
                zeroIndex++;
            }
            current++;
        }

    }
}

287. 寻找重复数

题目

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。
你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。

示例 1:

输入:nums = [1,3,4,2,2]
输出:2

示例 2:

输入:nums = [3,1,3,4,2]
输出:3

示例 3 :

输入:nums = [3,3,3,3,3]
输出:3

提示:

  • 1 <= n <= 105
  • nums.length == n + 1
  • 1 <= nums[i] <= n
  • nums 中 只有一个整数 出现 两次或多次 ,其余整数均只出现 一次

进阶:

  • 如何证明 nums 中至少存在一个重复的数字?
  • 你可以设计一个线性级时间复杂度 O(n) 的解决方案吗?

思路

本题条件比较特殊。

  1. 1 <= nums[i] <= n
  2. n.length = n + 1

所以,可以理解为找到成环链表的交叉节点的数组变形
i表示节点的值,nums[i]表示next指针。
题意nums[i]必重复,所以有两个指针指向同一个元素,即成环。
0表示从头开始遍历

答案

class Solution {
    public int findDuplicate(int[] nums) {
        int slow = 0, fast = 0;
        while (slow == 0 || slow != fast) {
            slow = nums[slow];
            fast = nums[nums[fast]];
        }

        fast = 0;
        while (slow != fast) {
            slow = nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
}

350. 两个数组的交集 II

题目

给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]

提示:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000

进阶:

  • 如果给定的数组已经排好序呢?你将如何优化你的算法?
  • 如果 nums1 的大小比 nums2 小,哪种方法更优?
  • 如果 nums2 的元素存储在磁盘上,内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?

思路

  1. 排序
  2. 双指针指向两个数组,哪个元素值小,移动哪个
  3. 相等就赋值,两个一起移动

答案

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        sort(nums1, 0, nums1.length - 1);
        sort(nums2, 0, nums2.length - 1);

        int current1 = 0;
        int current2 = 0;
        int[] result = new int[1000];
        int current = 0;

        while (current1 < nums1.length && current2 < nums2.length) {
            if (nums1[current1] == nums2[current2]) {
                result[current++] = nums1[current1];
                current1++;
                current2++;
            } else if (nums1[current1] < nums2[current2]) {
                current1++;
            } else {
                current2++;
            }
        }

        return Arrays.copyOf(result, current);
    }

    public void sort(int[] nums, int left, int right) {
        if (left >= right) {
            return;
        }

        int min = left, mid = min + 1, max = right;
        int element = nums[min];

        while (mid <= max) {
            int current = nums[mid];
            if (element < current) {
                swap(nums, mid, max--);
            } else if (element > current) {
                swap(nums, min++, mid++);
            } else {
                mid++;
            }
        }
        sort(nums, left, min - 1);
        sort(nums, max + 1, right);
    }

    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

977. 有序数组的平方

题目

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

示例 2:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums 已按 非递减顺序 排序

进阶:

  • 请你设计时间复杂度为 O(n) 的算法解决本问题

思路

  1. 有正负,两个指针一个指向头,一个指向尾,哪个绝对值小移动哪个
  2. 逆序,从大到小

答案

class Solution {
    public int[] sortedSquares(int[] nums) {
        int left = 0, right = nums.length - 1;
        int[] result = new int[nums.length];
        int current = right;
        while (left <= right) {
            if (Math.abs(nums[left]) < Math.abs(nums[right])) {
                result[current--] = nums[right] * nums[right];
                right--;
            } else {
                result[current--] = nums[left] * nums[left];
                left++;
            }
        }
        return result;
    }
}
  • 30
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值