leetCode沒那麽難啦 in Java (一)

分類:IT技術 時間:2017-10-02

前言

?? 感覺寫博客是一個很耗心力的東西T_T,簡單的寫了似乎沒什麽用,復雜的三言兩語也只能講個大概,呸呸...怎麽能有這些消極思想呢QAQ!那想來想去,先開一個leetcode的坑,雖然已經工作了,但是每天拿一兩道題打發打發也不錯嘛,不僅能鍛煉思維,還能復習一些算法思想,又不怎麽耗費時間撰寫...還能騙博客數...,額好像又說了啥內心的真實想法:)...

Go

兩數相加 Two Sum

  • Given an array of integers, return indices of the two numbers such that they add up to a specific target.
    You may assume that each input would have exactly one solution.
    Example:
    Given nums = [2, 7, 11, 15], target = 9,
    Because nums[0] + nums[1] = 2 + 7 = 9,
    return [0, 1].

  • 翻譯: 兩數之和
    給定一個整形數組和一個整數target,返回2個元素的下標,它們滿足相加的和為target。
    你可以假定每個輸入,都會恰好有一個滿足條件的返回結果,也就是多種答案的情況不予考慮
    例如給定了數組 nums = [2, 7, 11, 15], 需要的target = 9,
    因為 nums[0] + nums[1] = 2 + 7 = 9,
    所以返回 [0, 1]


  • 思路一
    暴力解法,好吧程序員做久了人有時候容易變傻,就好像現在讓你求從1加到100的和你想都不想for循環100次還說這是復雜度為O(n)哦,殊不知幾百年前還在讀小學的高斯就用求和公式O(1)時間就解決了T_T
    廢話說完了,既然暴力解法這麽傻,為啥還要講,因為很多題目實在想不到解法時,可以先擬定一個暴力解法,然後再在這上面去優化時間與空間,尋找思路。
    最簡單暴力解決就是多次遍歷,兩輪循環,把他們的和加起來,等於target就返回下標,如果啥都沒就返回[-1,-1]

    public int[] twoSum01(int[] arr, int target) {
    
        if (arr == null) return new int[]{-1, -1};
    
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[i] + arr[j] == target) return new int[]{i, j};
            }
        }
    
        return new int[]{-1, -1};
    }

    核心代碼就是中間的三行,很簡單的兩次遍歷,數據量如果是在\(10^4\)這個範圍內,\(O(n^2)\)級別的算法的時間在1秒內左右,所以如果數據量不是很大,這種暴力解法也是可以接受的。

  • 思路二
    \(O(n^2)\)的時間復雜度如果數據量很大自然是不能接受的,這裏就從上面的暴力算法改進,在思路一中,每次遍歷元素的時候都要把他和剩下的所有元素都比一遍,這真是太蠢了,你給一個小朋友做這道題他都不會這麽解,那小朋友怎麽解呢?
    假設數組內容是[2,7,11,15],目標值是17,那小朋友會先看2,17-2=15,那他就會去找有沒有15,有15就把他們的位置給記下來,沒有15就再看下一個數字。這裏我們再把這種想法優化一下,程序化一下,代碼如下

    public int[] twoSum(int[] nums, int target) {
        if (nums == null) return new int[]{-1, -1};
        Map<Integer, Integer> map = new HashMap<>();// 答案MAP,用於存儲答案,key為數字,value為在數字集合中下標位置
    
        for (int i = 0; i < nums.length; i++) {
            Integer exceptNum = target - nums[i];//期望的答案
            if (map.containsKey(exceptNum)) return new int[]{map.get(exceptNum), i}; //如果尋找到答案了,直接返回
            else map.put(nums[i], i); //如果沒有找到對應的答案,那麽就把這個數本身作為答案放入答案map,根據a+b=b+a,正在遍歷的數即是請求也是答案
        }
        return new int[]{-1, -1};
    }

    這裏最初的思路就是拿空間換時間,最簡單的處理是把所有的數組裏的數都放到哈希表中,然後直接遍歷get就可以了,但是這樣未免太浪費空間,所以引入第二步優化思路,我需要多少,我就存多少元素,利用加法交換律a + b = b + a,正在遍歷的元素同時就成為了備選答案存入map,這樣比單純的存入map中時間與空間的消耗期望值都是會少一些的。

總結

??題目很簡單,算法題也有很多,但是思路其實並沒有那麽繁雜,合理利用這些思路,理解了一道題,這一類的題目就都理解了。

  • 在沒有頭緒的時候先嘗試暴力解法,然後看看暴力解法裏哪一步是可以優化的,例如本題中最外層循環肯定是不可避免的,但是內循環對於每一個數字都遍歷所有就很沒有必要,就可以在這點上作優化
  • 空間換時間,哈希表往往是最常用的選擇之一,當然不僅僅是哈希表,樹,堆,圖,都是值得考慮的對象
  • 在使用空間換時間的優化中,充分利用已知的元素,最好能將已經遍歷的過的元素存儲再利用,這樣往往能降低不少空間使用與時間消耗,雖然都是O(N)級別的空間,但是前面的常數系數明顯是要小的。

Tags: 解法 target 一個 暴力 給定 相加

文章來源:


ads
ads

相關文章
ads

相關文章

ad