1. leetcode977. 有序数组的平方
1.1 题目描述
给你一个按 非递减顺序 排序的整数数组 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]
示例 3:
输入:nums = [-1]
输出:[1]
提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums 已按 非递减顺序 排序
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/squares-of-a-sorted-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
1.2 代码实现
1、我的提交
思路:首先找到负数和非负数的边界,指针 j 指向负数,指针 i 指向正数,每次比较 j 和 i 对应 数字平方后大小,选择小的放入结果数组,指针 j 和 i 分别向左向右挪动。由于两指针是从中间向两边走,因此最后需要判断两指针是否都走到数组边界,保证所有数字都被遍历到。
class Solution {
public int[] sortedSquares(int[] nums) {
int[] res = new int[nums.length];
int i = 0;
while(i < nums.length && nums[i] < 0){
i++;
}
int j = i == 0 ? 0 : (i-1);
int t = 0;
while(j >= 0 && i < nums.length){
int a = (int)Math.pow(nums[j], 2);
int b = (int)Math.pow(nums[i], 2);
if(a > b){
res[t++] = b;
i++;
}else if(a < b){
res[t++] = a;
j--;
}else{
// a == b
if(i != j){
// i != j 时需要放入两个a
res[t++] = a;
}
res[t++] = a;
i++;
j--;
}
}
while(j >= 0){
res[t++] = (int)Math.pow(nums[j--], 2);
}
while(i < nums.length){
res[t++] = (int)Math.pow(nums[i++], 2);
}
return res;
}
}
时间: O(n)。
2、推荐解法 - 参考官答
思路:指针 i 和 j 分别指向数组的首尾,每次比较两指针对应数字的平方,选择较大的逆序放入结果数组。由于两指针从首尾向中间走,因此该方法不需要判断指针是否走到数组边界的问题。
class Solution {
public int[] sortedSquares(int[] nums) {
int[] res = new int[nums.length];
int i = 0, j = nums.length - 1;
int t = j;
while(i <= j){
int a = nums[i] * nums[i];
int b = nums[j] * nums[j];
if(a > b){
res[t--] = a;
i++;
}else{
res[t--] = b;
j--;
}
}
return res;
}
}
时间:O(n)。
2. leetcode189. 旋转数组
2.1 题目描述
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
进阶:
尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。
你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?
示例 1:
输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右旋转 1 步: [7,1,2,3,4,5,6]
向右旋转 2 步: [6,7,1,2,3,4,5]
向右旋转 3 步: [5,6,7,1,2,3,4]
示例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]
示例3:
输入:nums[-1], k = 2
输出:[-1]
提示:
1 <= nums.length <= 2 * 104
-231 <= nums[i] <= 231 - 1
0 <= k <= 105
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/rotate-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2.2 代码实现
1、我的提交
思路:先对前 n-k 和 k 个元素分别进行翻转,然后再对整个数组进行翻转。
class Solution {
public void rotate(int[] nums, int k) {
//注意k的取值
if(k > nums.length){
k %= nums.length;
}
if(k == 0){
return;
}
swap(nums, 0, nums.length-k-1);
swap(nums, nums.length-k, nums.length-1);
swap(nums, 0, nums.length-1);
}
public void swap(int[] nums, int start, int end){
while(start < end){
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
}
时间:O(n).
2、其他思路
(1) 额外数组:开辟额外数组存放旋转后结果,位置对应关系为 i -> (i+k) mod n;
(2) 环状替换:为了省去额外数组的开销,可以使用临时变量存储目前被替换的元素,变量temp存储 nums[0],nums[0]应该放到 k 位置,temp存储nums[k],而nums[k] 应该放到 (k+k) mod n的位置上,依次类推,直至再到nums[0],一轮替换完成;因为一轮可能没有遍历到所有数字,因此从下个数字开始重复上述过程;用count记录被替换的元素个数控制替换过程的停止。
其他收获:求两个数字的最大公约数:
public int gcd(int x, int y) {
return y > 0 ? gcd(y, x % y) : x;
}