Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LeetCode] 360. Sort Transformed Array #360

Open
grandyang opened this issue May 30, 2019 · 0 comments
Open

[LeetCode] 360. Sort Transformed Array #360

grandyang opened this issue May 30, 2019 · 0 comments

Comments

@grandyang
Copy link
Owner

grandyang commented May 30, 2019

Given a sorted array of integers nums and integer values a , b and c. Apply a quadratic function of the form f( x ) = ax 2 + bx + c to each element x in the array.

The returned array must be in sorted order.

Expected time complexity: O( n )

Example 1:

Input: nums = [-4,-2,2,4], a = 1, b = 3, c = 5
Output: [3,9,15,33]

Example 2:

Input: nums = [-4,-2,2,4], a = -1, b = 3, c = 5
Output: [-23,-5,1,7]

Credits:
Special thanks to @elmirap for adding this problem and creating all test cases.

这道题给了一个数组,又给了一个抛物线的三个系数,让求带入抛物线方程后求出的数组成的有序数组。那么首先来看 O(nlgn) 的解法,这个解法没啥可说的,就是每个算出来再排序,这里用了最小堆来帮助我们排序,参见代码如下:

解法一:

class Solution {
public:
    vector<int> sortTransformedArray(vector<int>& nums, int a, int b, int c) {
        vector<int> res;
        priority_queue<int, vector<int>, greater<int>> q;
        for (auto d : nums) {
            q.push(a * d * d + b * d + c);
        }
        while (!q.empty()) {
            res.push_back(q.top()); q.pop();
        }
        return res;
    }
}; 

但是题目中的要求在 O(n) 中实现,那么只能另辟蹊径。其实这道题用到了大量的高中所学的关于抛物线的数学知识,我们知道,对于一个方程 f(x) = ax2 + bx + c 来说,如果 a>0,则抛物线开口朝上,那么两端的值比中间的大,而如果 a<0,则抛物线开口朝下,则两端的值比中间的小。而当 a=0 时,则为直线方法,是单调递增或递减的。那么这里可以利用这个性质来解题,题目中说明了给定数组 nums 是有序的,如果不是有序的,我想很难有 O(n) 的解法。正因为输入数组是有序的,可以根据a来分情况讨论:

当 a>0,说明两端的值比中间的值大,那么此时从结果 res 后往前填数,用两个指针分别指向 nums 数组的开头和结尾,指向的两个数就是抛物线两端的数,将它们之中较大的数先存入 res 的末尾,然后指针向中间移,重复比较过程,直到把 res 都填满。

当 a<0,说明两端的值比中间的小,那么从 res 的前面往后填,用两个指针分别指向 nums 数组的开头和结尾,指向的两个数就是抛物线两端的数,将它们之中较小的数先存入 res 的开头,然后指针向中间移,重复比较过程,直到把 res 都填满。

当 a=0,函数是单调递增或递减的,那么从前往后填和从后往前填都可以,可以将这种情况和 a>0 合并。

解法二:

class Solution {
public:
    vector<int> sortTransformedArray(vector<int>& nums, int a, int b, int c) {
        int n = nums.size(), i = 0, j = n - 1;
        vector<int> res(n);
        int idx = a >= 0 ? n - 1 : 0;
        while (i <= j) {
            if (a >= 0) {
                res[idx--] = cal(nums[i], a, b, c) >= cal(nums[j], a, b, c) ? cal(nums[i++], a, b, c) : cal(nums[j--], a, b, c);
            } else {
                res[idx++] = cal(nums[i], a, b, c) >= cal(nums[j], a, b, c) ? cal(nums[j--], a, b, c) : cal(nums[i++], a, b, c);
            }
        }
        return res;
    }
    int cal(int x, int a, int b, int c) {
        return a * x * x + b * x + c;
    }
}; 

Github 同步地址:

#360

类似题目:

Squares of a Sorted Array

参考资料:

https://leetcode.com/problems/sort-transformed-array/

https://leetcode.com/discuss/108831/java-o-n-incredibly-short-yet-easy-to-understand-ac-solution

LeetCode All in One 题目讲解汇总(持续更新中...)

(欢迎加入博主的知识星球,博主将及时答疑解惑,并分享刷题经验与总结,快快加入吧~)

知识星球 喜欢请点赞,疼爱请打赏❤️~.~

微信打赏

|

Venmo 打赏


---|---

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant