1. 程式人生 > 其它 >ARTS Week 2

ARTS Week 2

Algorithm

本週的 LeetCode 題目為 1. 兩數之和

題目簡介

給定一個整數陣列 nums 和一個整數目標值 target,找出該陣列中和為目標值 target 的那兩個 整數,並返回它們的陣列下標。你可以假設每種輸入只會對應一個答案。但是,陣列中同一個元素在答案裡不能重複出現。

示例 :

輸入:nums = [2,7,11,15], target = 9
輸出:[0,1]
解釋:因為 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

題目思路

題目的思路很簡單,遍歷陣列,查詢 target - nums[0] 是否在陣列 nums 中,若在返回 0 和它的下標,若不在,查詢下一個,即 target-nums[1] 是否在陣列中,直至找到停止。為了快速查詢 target-nums[i],可以記錄下陣列中的 值——索引 的對應關係。

最終程式碼

// 自己的寫法
class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer, HashSet<Integer>> numIndexMap = new HashMap<Integer, HashSet<Integer>>();
        for (int i = 0; i < nums.length; i++) {
            Integer num = nums[i];
            if (numIndexMap.containsKey(num) == false) {
                numIndexMap.put(num, new HashSet<Integer>());
                numIndexMap.get(num).add(i);
            } else {
                numIndexMap.get(num).add(i);
            }
        }
        int[] ans = new int[2];
        int index = 0;
        for (Integer key: numIndexMap.keySet()) {
            Integer goalKey = target - key;
            if (goalKey.equals(key) == true) {
                if (numIndexMap.get(goalKey).size() > 1) {
                    for (Integer temp: numIndexMap.get(goalKey)) {
                        ans[index] = temp;
                        index += 1;
                    }
                }
            } else {
                if (numIndexMap.containsKey(goalKey) == true) {
                    for (Integer temp: numIndexMap.get(key)) {
                        ans[0] = temp;
                    }
                    for (Integer temp: numIndexMap.get(goalKey)) {
                        ans[1] = temp;
                    }
                }
            }
        }
        return ans;
    }
}

但自己的寫法較為複雜,官方的寫法簡略。實際上沒有必要為每個元素都建立值—索引的對映關係,可以等到遍歷的時候進行判斷和建立。程式碼如下:

// 官方的寫法
class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer, Integer> numIndexMap = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; i++) {
            if (numIndexMap.containsKey(target - nums[i])) {
                return new int[]{numIndexMap.get(target - nums[i]), i};
            } else {
                numIndexMap.put(nums[i], i);
            }
        }
        return new int[2];
    }
}

Review

本週 Review 的英文文章為:Follow boring advice

這篇文章很短,作者分享了一些建議,這些建議在作者眼中是無聊枯燥的,我認為大部分是老調重談。雖說其中很多相信大部分人早已聽過,但做到卻並不是那麼容易,這就是知易行難。Review 這篇文章,一是希望能對大家有幫助,二是希望能提醒自己。

下面的就是作者分享的具體建議:

  • 行動(Action):無論什麼事,先做起來。我們是由我們所做的事決定的,而不是所想的事定義的。任何不完美的行動都比一直思考它更好;
  • 連貫(Consistency):好事是建立在一個好習慣並在堅持它的過程中發生。如定期鍛鍊身體;
  • 迭代(Iteration):需要不時地停下來,反思,調整繼續前進。一味地做而不去反思可能會在錯誤的道路上越走越遠;
  • 複利(Compounding):複利不僅適用於金融領域,同樣也適用於生活中,每個細微的改變也會隨著時間推移產生巨大影響;
  • 刻意練習(Deliberate practice):如果想要提高某項能力,重要的是有意識的刻意訓練它;
  • 專注(Focus):一次只做一件事,設立明確的目標,避免分心和衝動;
  • 分治法(Divide and conquer):將一個大的任務分割成一個個小的任務來完成;
  • 積極樂觀和感激(Positivity and gratitude):對生活要保持積極樂觀,對生活中的人要懷有感激之心。

Tip

快慢指標判斷條件的細微差異。

快慢主要用在連結串列中,簡單的說快慢指標就是慢指標一次只前進一步,而快指標一次會前進兩步,這樣快指標的就會先達到 null 後,停止迴圈。示例程式碼如下:

/**
 * Definition for singly-linked list.
 * 單鏈表定義
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */

ListNode slow = head;
ListNode fast = head;
while (判斷條件) {
	slow = slow.next;
	fast = fast.next.next;
}

判斷條件有兩種選擇,分別為:

  • (fast != null) && (fast.next != null)
  • (fast.next != null) && (fast.next.next != null)

當判斷條件是 (fast != null) && (fast.next != null) ,結束時慢指標所在的位置正好是後半部分的開始位置。示例如下:

1->2->3->4->5->null
s  s  s  s
f     f     f  f->end

1->2->3->4->null
s  s  s
f     f     f->end

而當判斷條件是 (fast.next != null) && (fast.next.next != null) ,結束時慢指標後半部分的開始位置的前一個,即正中間的位置(總個數為奇數)或者是前半部分的最後一個(總個數為偶數)。示例如下:

1->2->3->4->5->null
s  s  s
f     f     f->end

1->2->3->4->null
s  s
f     f->end

Share

連續四個月在朋友圈和QQ空間分享月度總結,可以基本視為養成了習慣。雖說並沒有會帶來特別大的改變,但還是收穫了不少,也感受到了一定的提升。每個評論的、點讚的人都可以視為監督者,感謝他們起到了監督自己、鞭策自己的作用,沒有他們自己很可能會在某些方面上會放縱一些。