leetcode之分治刷题总结1

leetcode之分治刷题总结1

1-多数元素
题目链接:题目链接戳这里!!!

思路1:因为多数元素就一个,直接升序排序,返回中间那个值,一定是升序元素。

class Solution {
    public int majorityElement(int[] nums) {
        Arrays.sort(nums) ;
        return nums[nums.length/2];
    }
}

leetcode之分治刷题总结1_第1张图片
思路2:借助HashMap,存储每个数字出现的次数,出现次数大于n/2,则该数字就是多数元素。

class Solution {
    public int majorityElement(int[] nums) {
        Map<Integer, Integer> map = new HashMap<>() ;
        int mid = nums.length / 2 ;
        for(int i=0; i<nums.length; i++){
            int count = map.getOrDefault(nums[i],0)+1 ;
            if(count>mid){
                return nums[i];
            }
            map.put(nums[i],count) ;
        }
        return nums[nums.length-1] ;
    }
}

leetcode之分治刷题总结1_第2张图片
思路3:分治思想,效率更高。

因为我们要找的是多数元素,那么我们将数组分成两部分,则至少有一部分的多数元素和数组的多数元素相同,那么这样,我们就可以用分治的思想了,递归求出左半数组的多数元素和右半数组的多数元素,如果二者相同,则该数就是数组的多数元素,如果不同,需要比较二者在数组中出现的次数,出现次数多的为多数元素。

AC代码如下:

class Solution {
    public int majorityElement(int[] nums) {
        return split(nums, 0, nums.length-1) ;
    }
    public int split(int [] nums, int left, int right){
        if(left==right){
            return nums[left] ;
        }
        int mid = (left+right)>>1 ;
        int leftMajor = split(nums,left,mid) ;
        int rightMajor = split(nums,mid+1,right) ;
        if(leftMajor==rightMajor){
            return leftMajor ;
        }
        return merge(nums, leftMajor, rightMajor, left, right) ;
    }
    public int merge(int [] nums, int leftMajor, int rightMajor, int left, int right){
        int countLeft = 0, countRight = 0 ;
        for(int i=left; i<=right; i++){
            if(nums[i]==leftMajor){
                countLeft ++ ;
            }
            if(nums[i]==rightMajor){
                countRight ++ ;
            }
        }
        return Math.max(countRight,countLeft)==countLeft ? leftMajor : rightMajor ;
    }
}

leetcode之分治刷题总结1_第3张图片

2-寻找两个正序数组中的中位数
题目链接:题目链接戳这里!!!

思路1:直接合并为一个数组,升序排序,找出中位数即可。该方法虽然能AC,但是时间复杂度O(n)。

AC代码如下:

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length ;
        int n = nums2.length ;
        int [] arr = new int [m+n] ;
        for(int i=0; i<m; i++){
            arr[i] = nums1[i] ;
        }
        for(int i=m; i<m+n; i++){
            arr[i] = nums2[i-m] ;
        }
        Arrays.sort(arr) ;
        if((arr.length&1) == 1){
            return arr[(m+n)/2] ;
        }else{
            return 1.0 * (arr[(m+n)/2]+arr[(m+n)/2-1]) / 2 ;
        }

    }
}

leetcode之分治刷题总结1_第4张图片
3- 数组中的第K个最大元素
题目链接:题目链接戳这里!!!

思路1:直接调库排序,然后输出第K大的就可以。这个效率已经很高了。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        Arrays.sort(nums) ;
        return nums[nums.length - k] ;
    }
}

leetcode之分治刷题总结1_第5张图片
思路2:快速排序法

快排是基于分治的思想,将数组分成两部分,将大于主元的放在右边,小于主元的放到左边,然后对左右进行递归排序,如果主元的下标等于nums.length-k则说明找到了,否则根据主元的位置,对左边数组或者右边数组继续排序。

效率杠杠滴!!!

class Solution {
    public int findKthLargest(int[] nums, int k) {
       return quickSort(nums, 0, nums.length-1, nums.length-k) ;
    }
    public int quickSort(int []nums, int left, int right, int idx){
        int q = partition(nums, left, right) ;

        if(q>idx){
            return quickSort(nums,0,q-1,idx) ;
        }else if(q<idx){
            return quickSort(nums,q+1,right,idx) ;
        }else{
            return nums[idx] ;
        }
    }
    public int partition(int [] arr, int p, int r){
        int idx = (int) (Math.random()*(r-p+1)) + p ;
        swap(arr, idx, p) ;
        int pivot = arr[p] ; //初始化主元
        int left = p + 1; //左侧扫描指针
        int right = r ; //右侧扫描指针
        while(left <= right){
            while(left <= right && arr[left] <= pivot){
                left ++ ;
            }
            while(left <= right && arr[right] >= pivot){
                right -- ;
            }
            if(left < right){ //找到左侧比主元大的,右侧比主元小的,二者交换
                swap(arr, left, right) ;
            }
        }
        swap(arr, p, right) ; //将初始化的主元与划分后得到的主元交换
        return right ;
    }
    public void swap(int []arr, int i, int j){
        int temp = arr[i] ;
        arr[i] = arr[j] ;
        arr[j] = temp ;
    }
}

leetcode之分治刷题总结1_第6张图片

4-摆动序列II
题目链接:题目链接戳这里!!!

思路:直接采用插孔的方式,先升序排序,然后然后从从往前选元素,依次插孔。

class Solution {
    public void wiggleSort(int[] nums) {
        Arrays.sort(nums) ;
      int [] array = new int [nums.length] ;
      int k=nums.length-1;
        for(int i=1;i<nums.length;i+=2)
        {
            array[i]=nums[k--];
        }

        for(int i=0;i<nums.length;i+=2)
        {
            array[i]=nums[k--];
        }

        for(int i=0; i<array.length; i++){
            nums[i] = array[i] ;
        }
    }
}

leetcode之分治刷题总结1_第7张图片
5-环形子数组的最大和
题目链接:题目链接戳这里!!!

思路:分为跨边界和没有跨边界两种情况。
如果没有跨界,依次遍历,找出最大和即可。
如果跨边界,需要记录总和减取最小和。

AC代码如下:

class Solution {
    public int maxSubarraySumCircular(int[] nums) {
        //分为跨边界和没跨边界两种情况
        int curMin, curMax, min, max, sum ;
        curMax = curMin = max = min = sum = nums[0] ;
        for(int i=1; i<nums.length; i++){
            sum += nums[i] ;
            curMax = curMax>0 ? curMax+nums[i] : nums[i] ;
            max = Math.max(max, curMax) ;
            curMin = curMin<0 ? curMin+nums[i] : nums[i] ;
            min = Math.min(min, curMin) ;
        }
        if(max<0){
            return max ;
        }
        return Math.max(max, sum-min) ;
    }
}

leetcode之分治刷题总结1_第8张图片
6-前K个高频元素
题目链接:题目链接戳这里!!!

思路1:用HashMap记录每个数字出现的次数,找到出现次数最多的,再通过HashMap依次对比输出出现次数前K多的元素即可。

AC代码如下:

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer,Integer> map = new HashMap<>() ;
        for(int i=0; i<nums.length; i++){
            map.put(nums[i],map.getOrDefault(nums[i],0)+1) ;
        }
        int maxTimes = 0 ;
        for(Map.Entry<Integer,Integer> entry : map.entrySet()){
            if(entry.getValue()>=maxTimes){
                maxTimes = entry.getValue() ;
            }
        }
        int [] res = new int [k] ;
        while(k>0){
            for(Map.Entry<Integer,Integer> entry : map.entrySet()){
                if(entry.getValue()==maxTimes){
                    res[k-1] = entry.getKey();
                    k -- ;
                }
            }
            maxTimes -- ;
        }
        return res ;
    }
}

leetcode之分治刷题总结1_第9张图片
思路2:基于快速排序的解法

思路如图所示,不过是把大的放到arr[q]左面,小的放到arr[q]右面.
leetcode之分治刷题总结1_第10张图片

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer,Integer> map = new HashMap<>() ;
        for(int i=0; i<nums.length; i++){
            map.put(nums[i],map.getOrDefault(nums[i],0)+1) ;
        }
       List<int[]> list = new ArrayList<>() ;
        for(Map.Entry<Integer,Integer> entry : map.entrySet()){
          list.add(new int[]{entry.getKey(),entry.getValue()}) ;
        }
        int [] res = new int [k] ;
        quickSort(list, 0, list.size()-1, res, 0, k) ;
        return res ;
    }
    public void quickSort(List<int[]>list, int start, int end, int [] res, int resIndex, int k){
        int p = (int)(Math.random()*(end-start+1)) + start ;
        Collections.swap(list,p,start) ;

        int pivot = list.get(start)[1] ;
        int idx = start ;
        for(int i=start+1; i<=end; i++){
            if(list.get(i)[1]>=pivot){
                Collections.swap(list,i,idx+1) ;
                idx ++ ;
            }
        } 
        Collections.swap(list, start, idx) ;


        if(k <=idx-start){
            quickSort(list, start, idx-1, res, resIndex, k) ;
        }else{
            for(int i=start; i<=idx; i++){
                res[resIndex++] = list.get(i)[0] ;
            }
            if(k>idx-start+1){
                quickSort(list,idx+1, end, res, resIndex, k-(idx-start+1)) ;
            }
        }
    }
}

leetcode之分治刷题总结1_第11张图片
道阻且长,行则将至,加油吧,少年!!!

你可能感兴趣的:(算法与数据结构,leetcode,排序算法,分治算法)