【算法】有序数组的平方

118 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情

题目

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

解题思路

关键词:非递减排序;平方;保持排序非递减

关键信息:数组有负数;平方计算后大小排序会变;计算结果会有变化

API耍流氓解法

如果数组中存在负数,当平方计算后数组中负数部分字段排序就会发生变化。输出新数组结果必须满足非递减排序就需要将负数部分前移翻转。最省事解决办法先将数组每个数进行平方计算然后调用api中Arrays.sort进行数组重排即可。(一个偷懒算法完成)

public int[] sortedSquares(int[] nums) {
   int[] ans = new int[nums.length];
   for (int i = 0; i < nums.length; ++i) {
       ans[i] = nums[i] * nums[i];
   }
   Arrays.sort(ans);
   return ans;
}

双指针解法

双指针算法思路先找到正负数边界(默认排好序但正负平方之后大小会变),正负两端大小比较后重新填充到新数组中得出结果。

  1. 首先遍历数组当数值大于0时表示数组中存在负数。
  2. 若数组中不存在负数情况,直接遍历数组计算平方数即可。
  3. 有负数的情况下设置两个指针,r表示正数部分,l表示负数部分,两个指针分别向右边和左边移动。
  4. 创建新数组保存排序结果,循环比较l和r对应值大小,小的入队并移动该指针。
  5. 预设前提条件任何一方指针位移结束遍历另外指针剩余值直到结束。
    public int[] sortedSquares(int[] nums) {
			int r = 0;
            int length = nums.length;
            if(length == 1){
                nums[0] *= nums[0];
                return nums;
            }  
            while(nums[r] < 0 && r < length - 1){ // 找到小数部分临界点
                r++;
            }
            if(r > 0 && nums[0] < 0){
                int[] newNums = new int[length]; // 新建数组用空间
                int l = r - 1; // l是小数部分起点
                int index = 0;
                while(l >= 0 || r < length){
                     // 右边剩余遍历填充
                    if(l < 0){
                        newNums[index++] = nums[r] * nums[r];
                        r++;
                       continue;
                    }
                    // 左边剩余遍历填充
                    if(r >= length){
                        newNums[index++] = nums[l] * nums[l];
                        l--;
                        continue;
                    }
                    // 左边小于右边
                    if(-nums[l] <= nums[r]){
                        newNums[index++] = nums[l] * nums[l];
                        l--;
                    }else if(-nums[l] > nums[r]){
                        newNums[index++] = nums[r] * nums[r];
                        r++;
                    } 
                }
                nums = newNums;
            }else{
                while(r < length){
                    nums[r] *= nums[r];
                    r ++;
                }
            }
            return nums;
    }

代码优化版本

根据上述算法其实可以优化为双指针首尾遍历(实时上找到正负边界还是对数组做全量遍历)。因此可将算法替换成从数组左右开始做比较(负数越小平方后越大)

 public int[] sortedSquares(int[] nums) {
    int  i =  nums.length;
        int left = 0;
        int right = i-1;
        int[] res = new int[i];
        while(left <= right){
            i--;
            if(nums[left]+nums[right]<0){
                res[i] = nums[left]*nums[left];
                left++;
            }else{
                res[i] = nums[right]*nums[right];
                right--;
            }
        }
        return res;
    }

参考