zoukankan      html  css  js  c++  java
  • [leetCode]88.合并两个有序数组

    在这里插入图片描述

    解法一 插入排序

    思路:因为两个数组是有序的,因此可以在nums1尾部插入一个元素,再对左半部分进行扫描将插入的元素放在合适位置。

    class Solution {
        public void merge(int[] nums1, int m, int[] nums2, int n) {
            for(int i = m; i < m+n; i++) {
                nums1[i] = nums2[i-m];
                for(int j = i; j > 0 && nums1[j] < nums1[j-1]; j--){
                    exch(nums1,j,j-1);
                }
            }
        }
    
        public void exch(int[] a, int i, int j){
            int temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
    }
    

    解法二 双指针

    思路:由于是归并两个有序数组直接就可以想到归并排序中的归并操作,nums1为输出数组,将nums1nums2数组中的值存储到aux辅助数组中,使用两个指针ij指向左半边开头与右半边开头,从左向右扫描,取左半边与右半边中较小的依次放入nums1中。

    class Solution {
        public void merge(int[] nums1, int m, int[] nums2, int n) {
            int[] aux = new int[m+n];//辅助数组
            for(int i =  0; i < m + n; i++)
                aux[i] = i < m? nums1[i]: nums2[i-m];
            int i = 0, j = m, k = 0;
            while(k < m+n){
                if(i==m) nums1[k] = aux[j++];//左边取完用右边
                else if(j==m+n) nums1[k] = aux[i++];//右边取完用左边
                else if(aux[i] < aux[j]) nums1[k] = aux[i++];//左边小于右边用左边
                else nums1[k] = aux[j++];//右边小于左边用右边
                k++;
            }
        }
    }
    

    解法三 二分查找

    思路:每次从nums2取出一个元素,通过二分查找查找该元素在nums1中的插入位置,将该位置及之后原有的的元素向后移动一位,给新元素腾位置,再将新元素插入。

    class Solution {
        public void merge(int[] nums1, int m, int[] nums2, int n) {
            for(int i = m; i < m+n; i++){
                int lo = 0, hi = i - 1;
                while(lo <= hi) {
                    int mid = lo + (hi - lo)/2;
                    if(nums1[mid] <= nums2[i-m]) lo = mid + 1;
                    else if (nums1[mid] > nums2[i-m]) hi = mid - 1;
                }
                for(int j = i; j > lo; j--){
                    nums1[j] = nums1[j - 1];
                }
                nums1[lo] = nums2[i-m];  
            }
        }
    
        public void exch(int[] a, int i, int j){
            int temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
    }
    

    上面代码中空间复制度为O(m+n)可以继续优化,只复制nums1中的元素到一个新数组中

    class Solution {
        public void merge(int[] nums1, int m, int[] nums2, int n) {
            int[] nums1_copy = new int[m];
            System.arraycopy(nums1, 0, nums1_copy, 0, m);
            int i = 0, j = 0, k = 0;
            while(i < m && j < n){
                nums1[k++] = nums1_copy[i] < nums2[j] ? nums1_copy[i++]:nums2[j++];
            }
            if(i < m)  System.arraycopy(nums1_copy, i, nums1, i+j, m+n-i-j);
            if(j < n)  System.arraycopy(nums2, j, nums1, i+j, m+n-i-j);         
        }
    }
    

    上面代码已经达到了最优的时间复杂度O(m+n),空间复杂度优化为了O(m),可以将指针指向数组尾部从后往前遍历,将较大的值放在nums1尾部

    class Solution {
        public void merge(int[] nums1, int m, int[] nums2, int n) {
            int i = m-1, j = n-1, k = m+n-1;
            while(i >= 0 && j >= 0){
                //比较nums1[i]与nums2[j]将较大的放在nums1尾部
                nums1[k--] = nums1[i] < nums2[j] ? nums2[j--]:nums1[i--];
            } 
            //补充nums2缺失的元素,nums1=[0],m=0,nums2=[1],n=1这种情况 
            System.arraycopy(nums2, 0, nums1, 0, j+1); 
        }
    }
    

    总结

    合并数组时可以从后往前复制,这样可以减少移动次数

  • 相关阅读:
    ntp时钟同步
    Office2013中文激活版
    Windows2008|2003超出最大连接数
    Vivaldi浏览器媲美Chrome
    Win10激活KMS2.0
    FTP下载工具
    UltraEdit编辑器|UE
    社工-入侵
    实时系统跟分时系统
    ThreadPoolExecutor线程池解析与BlockingQueue的三种实现
  • 原文地址:https://www.cnblogs.com/PythonFCG/p/13860016.html
Copyright © 2011-2022 走看看