977. 有序数组的平方

题目:https://leetcode-cn.com/problems/squares-of-a-sorted-array/

答案参考:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html#%E5%8F%8C%E6%8C%87%E9%92%88%E6%B3%95

暴力排序

最直观的相反,莫过于:每个数平方之后,排个序,美滋滋,代码如下:

C++

class Solution {
public:
    vector<int> sortedSquares(vector<int>& A) {
        for (int i = 0; i < A.size(); i++) {
            A[i] *= A[i];
        }
        sort(A.begin(), A.end()); // 快速排序
        return A;
    }
};

这个时间复杂度是 O(n + nlogn), 可以说是O(nlogn)的时间复杂度,但为了和下面双指针法算法时间复杂度有鲜明对比,记为 O(n + nlogn)。

双指针法

数组其实是有序的, 只不过负数平方之后可能成为最大数了。

那么数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。

此时可以考虑双指针法了,i指向起始位置,j指向终止位置。

定义一个新数组result,和A数组一样的大小,让k指向result数组终止位置。

如果A[i] * A[i] < A[j] * A[j] 那么result[k--] = A[j] * A[j]; 。

如果A[i] * A[i] >= A[j] * A[j] 那么result[k--] = A[i] * A[i]; 。

C++

class Solution {
public:
    vector<int> sortedSquares(vector<int>& A) {
        int k = A.size() - 1;
        vector<int> result(A.size(), 0);
        for (int i = 0, j = A.size() - 1; i <= j;) { // 注意这里要i <= j,因为最后要处理两个元素
            if (A[i] * A[i] < A[j] * A[j])  {
                result[k--] = A[j] * A[j];
                j--;
            }
            else {
                result[k--] = A[i] * A[i];
                i++;
            }
        }
        return result;
    }
};

此时的时间复杂度为O(n),相对于暴力排序的解法O(n + nlogn)还是提升不少的。

这里还是说一下,大家不必太在意leetcode上执行用时,打败多少多少用户,这个就是一个玩具,非常不准确。

做题的时候自己能分析出来时间复杂度就可以了,至于leetcode上执行用时,大概看一下就行,只要达到最优的时间复杂度就可以了,

一样的代码多提交几次可能就击败百分之百了.....

JAVA

class Solution {
    public int[] sortedSquares(int[] nums) {
        int right = nums.length - 1;
        int left = 0;
        int[] result = new int[nums.length];
        int index = result.length - 1;
        while (left <= right) {
            if (nums[left] * nums[left] > nums[right] * nums[right]) {
                result[index--] = nums[left] * nums[left];
                ++left;
            } else {
                result[index--] = nums[right] * nums[right];
                --right;
            }
        }
        return result;
    }
}

官方:https://leetcode-cn.com/problems/squares-of-a-sorted-array/solution/you-xu-shu-zu-de-ping-fang-by-leetcode-solution/

方法一:直接排序

最简单的方法就是将数组nums 中的数平方后直接排序。

C++class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> ans;//创建一个vector容器
        for (int num: nums) {
            ans.push_back(num * num);//将结果推入vector的末尾
        }
        sort(ans.begin(), ans.end());//排序
        return ans;
    }
};

JAVA版
class Solution {
    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;
    }
}

c++标准库里的排序函数的使用方法: https://www.cnblogs.com/epep/p/10959627.html

I)Sort函数包含在头文件为#include<algorithm>的c++标准库中,调用标准库里的排序方法可以不必知道其内部是如何实现的,只要出现我们想要的结果即可!

II)Sort函数有三个参数:

(1)第一个是要排序的数组的起始地址。

(2)第二个是结束的地址(最后一位要排序的地址)

(3)第三个参数是排序的方法,可以是从大到小也可是从小到大,还可以不写第三个参数,此时默认的排序方法是从小到大排序。

Sort函数使用模板: sort(start,end,排序方法)

从大到小的排序: 需要加入一个比较函数 complare(),此函数的实现过程是这样的

bool complare(int a,int b)
{
    return a>b;
}

结构体中的排序:

 struct node
 {
   int a;
   int b;
   double c;
 }

有一个node类型的数组node arr[100],想对它进行排序:先按a值升序排列,如果a值相同,再按b值降序排列,如果b还相同,就按c降序排列。就可以写这样一个比较函数:

 bool cmp(node x,node y)
 {
    if(x.a!=y.a) return x.a<y.a;
    if(x.b!=y.b) return x.b>y.b;
    return x.c>y.c;
 }

JAVA中的排序函数:https://www.cnblogs.com/zz22--/p/10705970.html

Arrays中的sort()方法主要是针对各种数据类型(基本数据类型和引用对象类型)的数组元素排序。

.......

关于引用对象类型数组的排序sort()方法要用到接口Comparator<T>,对其排序内部的比较函数compare()进行重写,以便于我们按照我们的排序要求对引用对象数组极性排序,默认是升序排序,但可以自己自定义成降序排序。关于Comparator<T>的介绍见官方文档

 

 

package test;
import java.util.Arrays;
import java.util.Comparator;
//用Arrays中的sort()对数组进行排序
public class test4 {
    //年龄比较器
    Comparator<student> comparatorAge =new Comparator <student>(){
        public int compare(student p1,student p2){
            if (p1.getAge()>p2.getAge())
                return 1;
            else if (p1.getAge()<p2.getAge())
                return -1;
            else
                return 0;
        }
    };
     
    //成绩比较器
    Comparator<student> comparatorGrade =new Comparator <student>(){
        public int compare(student p1,student p2){
            if (p1.getGrade()>p2.getGrade())
                return 1;
            else if (p1.getGrade()<p2.getGrade())
                return -1;
            else
                return 0;
        }
    };
     
    public student [] ageSort(student[] s){
        Arrays.sort(s,comparatorAge);
        return s;
    }
     
    public student [] gradeSort(student[] s){
        Arrays.sort(s,comparatorGrade);
        return s;
    }
     
    public static void main(String[] args) {
         test4 tt=new test4(); 
         student p1 = new student() ;
                 p1.setAge( 10 );
                 p1.setName( "p1" );
                 p1.setGrade( 98 );
                  
                 student p2 = new student() ;
                 p2.setAge( 30 );
                 p2.setName( "p2" );
                 p2.setGrade( 70 );
                  
                 student p3 = new student() ;
                 p3.setAge( 20 );
                 p3.setName( "p3" );
                 p3.setGrade( 83 );
                  
                 student p4 = new student() ;
                 p4.setAge( 15 );
                 p4.setName( "p4" );
                 p4.setGrade( 80 );
                  
        student [] list = {p1,p2,p3,p4} ;       
             
        student []agePrint=  tt.ageSort(list);
        for (student ss : agePrint) {
             System.out.println("student age sort ," + ss.getName() + "  " + ss.getAge() +" " +ss.getGrade());
         }//按年龄排序
         
        student []gradePrint=  tt.gradeSort(list);
        for (student ss : gradePrint) {
             System.out.println("student grade sort ," + ss.getName() + "  " + ss.getAge() +" " +ss.getGrade());
         }//按成绩排序
         
    }
 
}
 
//创建一个类型,用于比较的引用对象类型
class student{
    private String name;
    private int age;
    private float grade;
     
    public void setName(String name){
        this.name=name;
    }  
     
    public void setAge(int age) {
        this.age = age;
    }
     
    public void setGrade(float grade) {
        this.grade = grade;
    }
     
    public String getName() {
        return name;
    }
     
    public int getAge() {
        return age;
    }
 
    public float getGrade() {
        return grade;
    }   
 }

方法二:双指针

方法一没有利用「数组 nums 已经按照升序排序」这个条件。显然,如果数组nums 中的所有数都是非负数,那么将每个数平方后,数组仍然保持升序;如果数组nums 中的所有数都是负数,那么将每个数平方后,数组会保持降序。

这样一来,如果我们能够找到数组 nums 中负数与非负数的分界线,那么就可以用类似「归并排序」的方法了。具体地,我们设 neg 为数组nums 中负数与非负数的分界线,也就是说,nums[0] 到 nums[neg] 均为负数,而 nums[neg+1] 到 nums[n−1] 均为非负数。当我们将数组 nums 中的数平方后,那么 nums[0] 到 nums[neg] 单调递减,]nums[neg+1] 到 nums[n−1] 单调递增。

由于我们得到了两个已经有序的子数组,因此就可以使用归并的方法进行排序了。具体地,使用两个指针分别指向位置 neg 和neg+1,每次比较两个指针对应的数,选择较小的那个放入答案并移动指针。当某一指针移至边界时,将另一指针还未遍历到的数依次放入答案。

方法三:双指针(和代码随想录里面的一样)

同样地,我们可以使用两个指针分别指向位置 0 和 n−1,每次比较两个指针对应的数,选择较大的那个逆序放入答案并移动指针。这种方法无需处理某一指针移动至边界的情况,读者可以仔细思考其精髓所在。

 

posted @ 2021-10-11 09:10  wltree  阅读(115)  评论(0编辑  收藏  举报