1. 程式人生 > >乘風破浪:LeetCode真題_001_TwoSum

乘風破浪:LeetCode真題_001_TwoSum

乘風破浪:LeetCode真題_001_TwoSum

一、前言

    沉寂了很長時間,也悟出了很多的道理,寫作是一種業餘的愛好,是一種自己以後學習的工具,是對自己過往的經驗積累的佐證,是檢驗自己理解深入度的方法。在前面的模組之中,我們已經將基本的程式設計知識、資料結構、設計模式、應用框架、各種優化爛熟於心了,對程式開發有了一定的理解,但是程式設計的功力是一種水磨的功夫,需要問題,也需要思考,最重要的是需要自己用心的去打出程式碼,在這個過程中經驗、技巧、熟練度、思考力都是非常重要的,因此我們通過LeetCode上的一些題目來鍛鍊一下這方面的能力。

二、LeetCode真題_001_TwoSum

2.1 題目

2.2 分析與解決

    其實從問題我們就可以看出,這是類似於helloworld的一個題目,比較簡單,藉以引導我們從不同的角度使用不同的方法去解決問題。最簡單的想法就是暴力破解方法,通過窮舉所有的情況來解決問題,但是代價是時間複雜度O(n~2),空間複雜度O(1)。那麼有沒有其他方法呢,於是我們想到了hash表的方法,用空間換時間,通過一次遍歷就能找到所有的可能結果。

  通過暴力演算法來解決:

 1 public int[] twoSum(int[] nums, int target) {
 2     for (int
i = 0; i < nums.length; i++) { 3 for (int j = i + 1; j < nums.length; j++) { 4 if (nums[j] == target - nums[i]) { 5 return new int[] { i, j }; 6 } 7 } 8 } 9 throw new IllegalArgumentException("No two sum solution");
10 }

    通過hash演算法來解決,又分為兩次for迴圈和一次for迴圈:

public int[] twoSum(int[] nums, int target) {
    Map<Integer, Integer> map = new HashMap<>();
    for (int i = 0; i < nums.length; i++) {
        map.put(nums[i], i);
    }
    for (int i = 0; i < nums.length; i++) {
        int complement = target - nums[i];
        if (map.containsKey(complement) && map.get(complement) != i) {
            return new int[] { i, map.get(complement) };
        }
    }
    throw new IllegalArgumentException("No two sum solution");
}

 1 public int[] twoSum(int[] nums, int target) {
 2     Map<Integer, Integer> map = new HashMap<>();
 3     for (int i = 0; i < nums.length; i++) {
 4         int complement = target - nums[i];
 5         if (map.containsKey(complement)) {
 6             return new int[] { map.get(complement), i };
 7         }
 8         map.put(nums[i], i);
 9     }
10     throw new IllegalArgumentException("No two sum solution");
11 }

    來看看我們的演算法:

 1 import java.util.Arrays;
 2 
 3 public class Solution {
 4     private static class Node implements Comparable<Node> {
 5         int val;
 6         int idx;
 7 
 8         public Node() {
 9         }
10 
11         public Node(int val, int idx) {
12             this.val = val;
13             this.idx = idx;
14         }
15 
16         @Override
17         public int compareTo(Node o) {
18             if (o == null) {
19                 return -1;
20             }
21             return this.val - o.val;
22         }
23     }
24 
25 
26     /**
27      * 題目大意
28      * 給定一個整數陣列,找出其中兩個數滿足相加等於你指定的目標數字。
29      * 要求:這個函式twoSum必須要返回能夠相加等於目標數字的兩個數的索引,且index1必須要小於index2。
30      * 請注意一點,你返回的結果(包括index1和index2)都不是基於0開始的。你可以假設每一個輸入肯定只有一個結果。
31      *
32      * 解題思路
33      * 建立一個輔助類陣列,對輔助類進行排序,使用兩個指標,開始時分別指向陣列的兩端,看這兩個下標對應的值是否
34      * 等於目標值,如果等於就從輔助類中找出記錄的下標,構造好返回結果,返回。如果大於就讓右邊的下標向左移,
35      * 進入下一次匹配,如果小於就讓左邊的下標向右移動,進入下一次匹配,直到所有的資料都處理完
36      */
37 
38     public int[] twoSum(int[] nums, int target) {
39         int[] result = {0, 0};
40 
41         Node[] tmp = new Node[nums.length];
42         for (int i = 0; i < nums.length; i++) {
43             tmp[i] = new Node(nums[i], i);
44         }
45 
46         Arrays.sort(tmp);
47 
48         int lo = 0;
49         int hi = nums.length - 1;
50 
51 
52         while (lo < hi) {
53             if (tmp[lo].val + tmp[hi].val == target) {
54 
55                 if (tmp[lo].idx > tmp[hi].idx) {
56                     result[0] = tmp[hi].idx ;
57                     result[1] = tmp[lo].idx ;
58                 } else {
59                     result[0] = tmp[lo].idx ;
60                     result[1] = tmp[hi].idx ;
61                 }
62                 break;
63             } else if (tmp[lo].val + tmp[hi].val > target) {
64                 hi--;
65             } else {
66                 lo++;
67             }
68         }
69         return result;
70     }
71 }

    這種想法也比較巧妙,先對所有元素進行排序,然後通過定義首尾兩個指標來不斷地逼近最後的和,直至遍歷完成,非常的巧妙,時間複雜度O(n),空間複雜度O(n)。不過也增加了額外的建立物件的空間。

 

 

 

三、總結

    通過這個簡單的問題,我們明白了對於一件事情,要麼使用時間換取空間,要麼使用空間換取時間,最後達到我們想要的結果,往往通過空間換取時間的比較多,因此hash演算法就變得非常的重要了,當然也有其他的演算法。