LeetCode演算法題-Merge Sorted Array(Java實現)
這是悅樂書的第161次更新,第163篇原創
01 看題和準備
今天介紹的是LeetCode演算法題中Easy級別的第20題(順位題號是88)。給定兩個排序的整數陣列nums1和nums2,將nums2中的元素合併到nums1中,並且作為一個排序的陣列。在nums1和nums2中初始化的元素個數分別為m和n。假設nums1有足夠的空間(大於或等於m + n)來儲存nums2中的其他元素。例如:
輸入:nums1 = [1,2,3,0,0,0],m = 3,nums2 = [2,5,6],n = 3
輸出:[1,2,2,3,5,6]
本次解題使用的開發工具是eclipse,jdk使用的版本是1.8,環境是win7 64位系統,使用Java語言編寫和測試。
02 第一種解法
給的條件很清晰,nums1的長度大於等於m+n的和,nums2的元素是肯定可以全部放進nums1的,既如此,那我們是不是可以先把nums2中的元素新增進nums1,從下標m開始,移入n個新的元素,然後再對nums1進行排序,最後得到新的nums1陣列。排序演算法使用了氣泡排序,當然使用其他的排序演算法也是可以的。
public void merge(int[] nums1, int m, int[] nums2, int n) { for (int i=m, k=0; i<nums1.length && k < n ; i++,k++) { nums1[i] = nums2[k]; } for (int j=0; j<nums1.length-1; j++) { for (int h=0; h<nums1.length-1-j; h++) { if (nums1[h] > nums1[h+1]) { int temp = nums1[h+1]; nums1[h+1] = nums1[h]; nums1[h] = temp; } } } }
03 第二種解法
上面的解法的時間複雜度是O(n^2),那能不能再降低點?讓其更快一點?讓我們來藉助例子分析下。
nums1 = [1,2,3,0,0,0],m = 3
nums2 = [2,5,6],n = 3
既然最後結果是將新的nums1排序,那麼按照升序來排,兩個陣列中最大的一個值肯定在第m+n位。
第一步,分別獲取nums1的第3位元素、nums2的第3位元素,比較兩數大小,數值大的放在nums1的第6位,此時nums1變成了[1,2,3,0,0,6]。
第二步,分別獲取nums1的第3位元素、nums2的第2位元素,比較兩數大小,數值大的放在nums1的第5位,此時nums1變成了[1,2,3,0,5,6]。因為第一步是將nums2的元素移到了nums1,所以nums2向前移動一位,但是nums1的第3位並沒有完全確定大小,所以保持不動。
第三步,分別獲取nums1的第3位元素、nums2的第1位元素,比較兩數大小,數值大的放在nums1的第4位,此時nums1變成了[1,2,3,3,5,6]。
第四步,分別獲取nums1的第2位元素、nums2的第1位元素,比較兩數大小,數值大的放在nums1的第3位,此時nums1變成了[1,2,2,3,5,6]。
依據上面的步驟,可以很快的寫出程式碼,但是有種特殊情況要考慮,當nums1的最小值,也就是nums1的第一位元素,它比nums2的最大值都大的時候,nums2的元素是要全部移到nums1原元素的前面,此時在迴圈完後,就要加多一個判斷,判斷nums2的元素下標是否已經移動到了第一位。
public void merge2(int[] nums1, int m, int[] nums2, int n) {
int i = m - 1;
int j = n - 1;
while (i >= 0 && j >= 0) {
if (nums1[i] > nums2[j]) {
nums1[i + j + 1] = nums1[i];
i--;
} else {
nums1[i + j + 1] = nums2[j];
j--;
}
}
while (j >= 0) {
nums1[i + j + 1] = nums2[j];
j--;
}
}
04 驗證與測試
為了驗證上面兩種解法的正確性和效率,我們使用了一些資料來測試。
public static void main(String[] args) {
Easy_088_MergeSortedArray instance = new Easy_088_MergeSortedArray();
int[] nums1 = {1,2,2,3,4,5,0,0,0};
int m = 6;
int[] nums2 = {2,5,8};
int n = 3;
long start = System.nanoTime();
instance.merge(nums1, m, nums2, n);
long end = System.nanoTime();
System.out.println("merge---輸出:"+Arrays.toString(nums1)+" , 用時:"+(end-start)/1000+"微秒");
int[] nums3 = {1,2,2,3,4,5,0,0,0};
int m2 = 6;
int[] nums4 = {2,5,8};
int n2 = 3;
long start2 = System.nanoTime();
instance.merge2(nums3, m2, nums4, n2);
long end2 = System.nanoTime();
System.out.println("merge2---輸出:"+Arrays.toString(nums1)+" , 用時:"+(end2-start2)/1000+"微秒");
}
測試結果如下
merge---輸出:[1, 2, 2, 2, 3, 4, 5, 5, 8] , 用時:4微秒
merge2---輸出:[1, 2, 2, 2, 3, 4, 5, 5, 8] , 用時:2微秒
從執行時間來看,解法二是明顯優於解法一的,解法二的時間複雜度是O(n)。
05 小結
可能有人會想到藉助Arrays.sort()方法來排序,但是如果是面試的時候,還是使用解法二好些。
以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!