『Leetcode』排序-剑指offer

问题(共八道)

  1. 剑指 Offer 03. 数组中重复的数字
  2. 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
  3. 剑指 Offer 39. 数组中出现次数超过一半的数字
  4. 剑指 Offer 45. 把数组排成最小的数
  5. 剑指 Offer 61. 扑克牌中的顺子
  6. 快排、堆排:215. 数组中的第K个最大元素
  7. 桶排序:347. 前 K 个高频元素
  8. 451. 根据字符出现频率排序

1. 剑指21. 思路

奇数在前,偶数在后,依然是双指针问题。
由于遍历整个数组,时间复杂度为:O(n),原数组中每个元素只遍历一次。由于是原地交换,空间复杂度:O(1)。

解决方案-双指针模板

class Solution {
    
    
    public int[] exchange(int[] nums) {
    
    
        int i=0,j=nums.length-1;
        if(nums==null) return nums;

        while(i<j){
    
    
            //记得:每一个while都要判断一次i<j or i<nums.length-1,防止数组越界
            while(i<j && nums[i]%2!=0){
    
    
                i++;
            }
            //i<j or j>0
            while(i<j && nums[j]%2==0){
    
    
                j--;
            }
            if(i<j){
    
    
                swap(nums,i,j);
                i++;
                j--;
            }
        }
        return nums;

    }

    public void swap(int[] nums,int i,int j){
    
    
        int temp=nums[i];
        nums[i]=nums[j];
        nums[j]=temp;
    }
}

2. 剑指39-思路

在这里插入图片描述

解决方案

法1:哈希表

时间复杂度:O(n)。其中 n 是数组 nums 的长度。
空间复杂度:O(n)。哈希表最多包含n- ⌊n/2⌋个键值对,所以占用的空间为 O(n)。这是因为任意一个长度为 n 的数组最多只能包含 n 个不同的值,但题中保证 nums 一定有一个众数,会占用(最少) ⌊n/2⌋+1个数字。因此最多有 n−(⌊n/2⌋+1)个不同的其他数字,所以最多有n- ⌊n/2⌋个不同的元素。
在这里插入图片描述

class Solution {
    
    
    public int majorityElement(int[] nums) {
    
    
        //计算nums数组出现的个元素个数,记录在哈希表中
        Map<Integer,Integer> counts=majorCount(nums);
        //记录出现次数最大的元素键值对
        Map.Entry<Integer,Integer> majority=null;
        for(Map.Entry<Integer,Integer> entry:counts.entrySet()){
    
    
            if(majority==null || entry.getValue()>majority.getValue()){
    
    
                majority=entry;
            }
        }
        return majority.getKey();

    }

    //返回哈希表中value最大数key。其中键值对为:key:nums元素;value:元素出现的次数
    public Map<Integer,Integer> majorCount(int[] nums){
    
    
         //计算nums数组出现的个元素个数,记录在哈希表中
        Map<Integer,Integer> counts=new HashMap<Integer,Integer>();
        for(int num:nums){
    
    
            if(!counts.containsKey(num)){
    
    
                counts.put(num,1);
            }else{
    
    
                counts.put(num,counts.get(num)+1);
            }         
        }
        return counts;
    }

}

法2:摩尔投票法——空间复杂度上改进

时间复杂度:O(n)。Boyer-Moore 算法只对数组进行了一次遍历。
空间复杂度:O(1)。Boyer-Moore 算法只需要常数级别的额外空间。
在这里插入图片描述

class Solution {
    
    
    public int majorityElement(int[] nums) {
    
    
        int voted=0,can=0;
        
        for(int num:nums){
    
    
            if(voted==0){
    
    
                can=num;
            }
            voted+=(num==can)?1:-1;
        }
        return can;
    }
}

法3:先排序,找到下标为⌊n/2⌋的元素(下标从 0 开始)一定是众数。
十种排序方法sort以及各方法的复杂度分析

时间复杂度:O(nlog⁡n)。将数组排序的时间复杂度为 O(nlog⁡n)。

空间复杂度:O(log⁡n)。如果使用语言自带的排序算法,需要使用 O(log⁡n)的空间。如果自己编写堆排序,则只需要使用 O(1)的额外空间。
在这里插入图片描述

//java版本
class Solution {
    
    
    public int majorityElement(int[] nums) {
    
    
        int n=nums.length;
        //先排序:从小到大
        Arrays.sort(nums);

        //返回下标为n/2的元素
        return nums[n/2];
    }
}

//cpp版本
class Solution {
    
    
public:
    int majorityElement(vector<int>& nums) {
    
    
        sort(nums.begin(), nums.end());
        return nums[nums.size() / 2];
    }
};

猜你喜欢

转载自blog.csdn.net/JingYan_Chan/article/details/127610939