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

    总结

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

  • 相关阅读:
    PAT 解题报告 1009. Product of Polynomials (25)
    PAT 解题报告 1007. Maximum Subsequence Sum (25)
    PAT 解题报告 1003. Emergency (25)
    PAT 解题报告 1004. Counting Leaves (30)
    【转】DataSource高级应用
    tomcat下jndi配置
    java中DriverManager跟DataSource获取getConnection有什么不同?
    理解JDBC和JNDI
    JDBC
    Dive into python 实例学python (2) —— 自省,apihelper
  • 原文地址:https://www.cnblogs.com/PythonFCG/p/13860016.html
Copyright © 2011-2022 走看看