leetcode之分治刷题总结1

Posted nuist__NJUPT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode之分治刷题总结1相关的知识,希望对你有一定的参考价值。

leetcode之分治刷题总结1

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

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

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


思路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] ;
    


思路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 ;
    

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 ;
        

    


3- 数组中的第K个最大元素
题目链接:题目链接戳这里!!!

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

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


思路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 ;
    

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] ;
        
    


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) ;
    


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 ;
    


思路2:基于快速排序的解法

思路如图所示,不过是把大的放到arr[q]左面,小的放到arr[q]右面.

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

leetcode之数论与模拟刷题总结1

leetcode之回溯刷题总结1

leetcode之贪心算法刷题总结1

leetcode之哈希表刷题总结1

leetcode之DFS+BFS+DSU刷题总结1