1. 程式人生 > >Leetcode進階----學習(一)【兩數相加、無重複字元的最長字串】

Leetcode進階----學習(一)【兩數相加、無重複字元的最長字串】

兩數相加

給定兩個非空連結串列來表示兩個非負整數。位數按照逆序方式儲存,它們的每個節點只儲存單個數字。將兩數相加返回一個新的連結串列。

你可以假設除了數字 0 之外,這兩個數字都不會以零開頭。

示例:

輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出:7 -> 0 -> 8
原因:342 + 465 = 807

1.此題解決思想比較簡單,直接設定一個進位carry,由於連結串列是按照逆序儲存的,計算兩數之和就可以直接從首節點開始計算求和,然後每次求得的和需要計算出該位的進位,即新進位carry = sum/10,在這裡需要建立一個新連結串列用來儲存求得的和(通過new建立)

,然後依次計算每一位之和並加到新連結串列之中,若某個連結串列達到尾部,則繼續計算另一個連結串列,遍歷完之後,觀察進位carry是否存在進位,若存在進位則將1加到新連結串列尾部,最後返回新連結串列:

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* dummyRoot = new ListNode(0);    //建立新連結串列儲存求和資料
        ListNode* p = dummyRoot;                 //定義指標p指向新連結串列
        int carry = 0;
        while (l1 || l2)                       //只有同時為空時,才退出
        {
            int x = l1 ? l1->val : 0;            //判斷連結串列l1是否為空,不為空則取出資料
            int y = l2 ? l2->val : 0;           //判斷連結串列l2是否為空,不為空則取出資料
            int sum = x + y + carry;           //計算兩數之和
            carry = sum/10;                    //計算新進位
            p->next = new ListNode(sum%10);    //建立新連結串列中的新節點
            p = p->next;
            if (l1)                            //如果不為空,繼續遍歷
                l1 = l1->next;                 
            if (l2)
                l2 = l2->next;
        }
        if (carry == 1)                       //判斷是否存在進位,存在則把1加到新連結串列中
            p->next = new ListNode(1);
        return dummyRoot->next;
    }
};

2.該題還有一種變形,即兩個數不是按照逆序存在連結串列中,而是正序,有興趣可以參考下Grandyang的部落格,具體做法有兩種,一種是將連結串列翻轉,然後使用上述的方法求和;另一種不採用翻轉連結串列,有點複雜,感興趣的同學可以自己去了解。。。

 

 

 

無重複字元的最長字串

給定一個字串,找出不含有重複字元的最長子串的長度。

示例 1:

輸入: "abcabcbb"
輸出: 3 
解釋: 無重複字元的最長子串是 "abc",其長度為 3。

示例 2:

輸入: "bbbbb"
輸出: 1
解釋: 無重複字元的最長子串是 "b"
,其長度為 1。

示例 3:

輸入: "pwwkew"
輸出: 3
解釋: 無重複字元的最長子串是 "wke",其長度為 3。
     請注意,答案必須是一個子串"pwke" 是一個子序列 而不是子串。

1.使用set容器儲存字元,如果之前未出現則存入set中,如果出現相同字元則從上一個left開始刪除,刪除到重複字元為止,其中記錄下最大子串長度:

具體分析:

若字串為abbca

首先i=0,存入set,此時set中存有字元a,更新cnt為1

i=1,沒有相同,存入set,此時set中存有字元a、b,更新cnt為2

i=2,出現相同字元b,則從上一個left = 0開始刪除,刪除後set中無元素,此時st.size()為0

刪除過後i=2,此時set中沒有相同,存入b,st.size()為1,小於之前cnt,不更新

i=3,存入c,此時st.size()為2,不更新

i=4,存入a,此時st.size()為3,更新cnt為3,則此為最大長度,最大字串為bca

class Solution {
public:
	int lengthOfLongestSubstring(string s) {
        int cnt = 0,left = 0,n = s.size();
        unordered_set<char> st;      //儲存出現的字元
        int i = 0;
        while (i < n)
        {
            if (!st.count(s[i]))  //未出現相同字元,則將字元插入set中,並更新子串長度為當前最大
            {
                st.insert(s[i++]);   //插入當前字元,下移一位
                cnt = max(cnt, (int)st.size());
            }
            else
                st.erase(s[left++]);    //出現相同字元則從上一個left開始刪除,直到重複字元為止
        }
        return cnt;
	}
};

2.使用hashmap來建立字元與其位置之間的聯絡,具體使用left標記重複字元的位置,根據該left得出最大長度:

具體分析:

若字串為abbca

根據該思路,首先建立聯絡

i=0:left為0,字元‘a'位置為1,res長度為1

i=1:left為0,字元’b‘位置為2,res長度為2

i=2:出現重複字元’b',此時更新left的位置,使其指向上一個‘b’出現的位置2,更新新‘b'的位置為3,更新res長度為1

i=3:left為2,字元‘c’位置為4,res長度為2

i=4:left為2,字元’a‘位置更新為5,res長度更新為3

返回3

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int res = 0, left = 0, i = 0, n = s.size();
        unordered_map<char, int> m;     //建立字元與其位置的聯絡
        for (int i = 0; i < n; ++i) {   //遍歷陣列,若出現重複字元則更新left的位置,使其指向重複字元
            left = max(left, m[s[i]]);
            m[s[i]] = i + 1;
            res = max(res, i - left + 1);  //根據left計算最大長度
        }
        return res;
    }
};