【LeetCode - 360】有序转化数组

1、题目描述

在这里插入图片描述

2、解题思路

  本题考的是数学,把输入数组 nums[] 看成横坐标,把输出的数组 ans[] 看成纵坐标。

f(x) = ax² + bx + c

定义一个函数:

public int cal(int x, int a, int b, int c) {
    return a * x * x + b * x + c;
}

  1、a == 0 且 b == 0

  此时 f(x) = c,输出数组 ans[] 的所有值均为 c。

  2、a == 0 且 b > 0

  此时 f(x) = bx + c,为单调递增函数,把 nums[] 的每个值进行 cal 计算赋值到 ans[] 即可。

  3、a == 0 且 b < 0

  此时 f(x) = bx + c,为单调递减函数,把 nums[] 的逆序每个值进行 cal 计算顺序赋值到 ans[] 即可。

  4、a > 0

  此时 f(x) = ax² + bx + c 为开口向上的抛物线,有最小值,最小值横坐标为 mid = -b/2a。

  如果我们从 nums[] 中找到距离 mid 最近的,然后当成最小值,赋值给 nums[0],这样操作很繁琐,因为每次都要从 nums[] 找距离 mid 最近的值。我们可以从大到小来赋值。

  我们直到,距离 mid 越远的横坐标,它的纵坐标就越大,因此,我们定义两个左右指针为 left = 0, right = nums.length-1,再定义一个 index = nums.legth-1 作为 ans[] 最大值的索引。

  1、比较 left - mid 和 rigth - mid 谁的绝对值大,大的那个就是距离 mid 最远的那个;

  2、比如 left 距离 mid 最远,则 ans[index] = cal(nums[left],a,b,c),完成最大值赋值;

  3、赋值好了最大值,我们调整 left++ 为新的 left,right 不变,index-- 表示找第二大。

  循环重复 1 2 3,直到遍历完所有的 nums[] ,此时 ans[] 也赋值完毕。

3、解题代码

class Solution {
    public int[] sortTransformedArray(int[] nums, int a, int b, int c) {
        // 把 nums[] 看成横坐标,把 ans[] 看成纵坐标
        int[] ans = new int[nums.length];
        int index;
        if (a == 0) {  // a==0 是直线
            if (b > 0) {   // 斜率为正,单调递增
                index = 0;
                for (int num : nums) {
                    ans[index++] = cal(num, a, b, c);
                }
            } else if (b < 0) {    // 斜率为负,单调递减
                index = nums.length - 1;
                for (int num : nums) {
                    ans[index--] = cal(num, a, b, c);
                }
            } else { // 水平直线
                Arrays.fill(ans, c);
            }
        } else {  // a != 0 是抛物线
            double midVal = -b * (1.0 / (2 * a));   // -b/2a 是抛物线的最值
            int left = 0;
            int right = nums.length - 1;
            if (a > 0) {    // 开口向上,有最小值
                index = nums.length - 1;    // 从最大值往下装入 ans 中
                while (left <= right) {
                    // x 距离中心横坐标越远的,y 越大
                    if (Math.abs(midVal - nums[left]) > Math.abs(midVal - nums[right])) {
                        ans[index] = cal(nums[left], a, b, c);
                        left++;
                    } else {
                        ans[index] = cal(nums[right], a, b, c);
                        right--;
                    }
                    index--;
                }
            } else {    // 开口向下,有最大值
                index = 0;
                while (left <= right) {
                    // x 距离中心横坐标越远的,y 越小
                    if (Math.abs(midVal - nums[left]) > Math.abs(midVal - nums[right])) {
                        ans[index] = cal(nums[left], a, b, c);
                        left++;
                    } else {
                        ans[index] = cal(nums[right], a, b, c);
                        right--;
                    }
                    index++;
                }
            }
        }
        return ans;
    }

    public int cal(int x, int a, int b, int c) {
        // ax² + bx + c
        return a * x * x + b * x + c;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值