leetcode C++

文章目錄

C++版的leetcode,從頭再來!java

1.兩數之和(hash)

下面這個代碼在return的時候一直遇到問題:node

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int length = sizeof(nums)/sizeof(nums[0]);
        for(int i = 0;i < length;++i)       
            for(int j = 0; j<length;++i)
                if (nums[i] + nums[j] == target)
                {
                    
                    return {nums[i],nums[j]};
                }
    
    }
};

後來改正的:python

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        int length = nums.size();
        vector<int> ans;
        for(int i = 0;i < length;i++)       
            for(int j = i + 1; j<length;j++)
                if (nums[i] + nums[j] == target)
                {
                    ans.push_back(i);
                    ans.push_back(j);
                    return ans;
                }
    return ans;
    }
};

幾點說明:
1.一個函數是必須有返回值的,若是隻有if里加了return,當出現else的 狀況這個函數就沒有了,因此要加else,要麼最後加return也行;
2.返回一個列表時,能夠定義一個容器來裝
3.計算數組長度用size()函數;
用暴力法就沒有意義了,測試用例必定後面的過不了
一開始想對數組進行排序,這樣能夠極大程度的進行剪枝,可是排序以後丟失了原有的下標,若是返回的是元素不是下標的話這樣就是可行的,可是下標不能用這種方法
哈希表的方法:ios

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {

        unordered_map<int,int> m;

        for(int i=0;i<nums.size();i++)
            m[nums[i]] = i;         //向map中添加元素
        
        for(int i=0;i<nums.size();i++)
        {
            if(m.find(target-nums[i]) != m.end() && m[target-nums[i]] != i)     //若是m中存在對應的鍵值,而且不爲i,後面這個條件很重要,由於會有重複的元素
                return {i , m[target-nums[i]]};
        }
        return {};
    }
};

做者:zrita
連接:https://leetcode-cn.com/problems/two-sum/solution/c-san-chong-fang-fa-jian-dan-yi-dong-ji-bai-100-z-/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

2. 兩數相加(鏈表)

能夠說有思路,先補齊不齊的,而後再添加到新的鏈表中,最後考慮進位,可是代碼過長既浪費時間又容易出錯git

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        ListNode* temp1 = l1;
        int len1 = 0;
        while(temp1)
        {
            temp1 = temp1->next;
            len1++;
        }
        ListNode* temp2 = l2;
        int len2 = 0;
        while(temp2)
        {
            temp2 = temp2->next;
            len2++;
        }
        temp1 =l1;
        while(temp1->next)
        {
            temp1 = temp1->next;
        }
        temp2=l2;
        while(temp2->next)
        {
            temp2=temp2->next;
        }
        while(len1 <len2)
        {
            ListNode* zero = new ListNode(0);
            temp1->next=zero;
            temp1 = zero;
            len1++; 
        }      
        while(len2<len1)
        {
            ListNode* zero = new ListNode(0);
            temp2->next = zero;
            temp2 = zero ;
            len2++;
        }
        ListNode* head = new ListNode(l1->val+l2->val);
        ListNode* temp = head;
        temp1=l1;
        temp1 = temp1->next;
        temp2=l2;
        temp2 = temp2->next;
        while(len1-1)
        {
            ListNode* cur = new ListNode(temp1->val+temp2->val);
            temp1=temp1->next;
            temp2=temp2->next;
            temp->next = cur;
            temp = cur;
            len1--;
        }
        temp = head;
        while(temp->next)
        {
            if(temp->val>=10)
            {
                temp->val -=10;
                temp->next->val +=1;
            }
            temp =temp->next;
        }
        if(temp->val>=10)
        {
            ListNode* zero = new ListNode(1);
            temp->val -=10;
            temp->next = zero; 
        }
        return head;
    }
};

相同的思路更簡潔的代碼
裏面值得學習的地方是新建一個頭節點,可是不許備放在終鏈表中,這樣不用再把中間過渡的一些代碼寫出來
還有就是新建節點的時候直接new就能夠的web

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
        int len1=1;//記錄l1的長度
        int len2=1;//記錄l2的長度
        ListNode* p=l1;
        ListNode* q=l2;
        while(p->next!=NULL)//獲取l1的長度
        {
            len1++;
            p=p->next;
        }
        while(q->next!=NULL)//獲取l2的長度
        {
            len2++;
            q=q->next;
        }
        if(len1>len2)//l1較長,在l2末尾補零
        {
            for(int i=1;i<=len1-len2;i++)
            {
                q->next=new ListNode(0);
                q=q->next;
            }
        }
        else//l2較長,在l1末尾補零
        {
            for(int i=1;i<=len2-len1;i++)
            {
                p->next=new ListNode(0);
                p=p->next;
            }
        }
        p=l1;
        q=l2;
        bool count=false;//記錄進位
        ListNode* l3=new ListNode(-1);//存放結果的鏈表
        ListNode* w=l3;//l3的移動指針
        int i=0;//記錄相加結果
        while(p!=NULL&&q!=NULL)
        {
            i=count+p->val+q->val;
            w->next=new ListNode(i%10);
            count=i>=10?true:false;
            w=w->next;
            p=p->next;
            q=q->next;
        }
        if(count)//若最後還有進位
        {
            w->next=new ListNode(1);
            w=w->next;
        }
        return l3->next; 
    }
};

做者:chenlele
連接:https://leetcode-cn.com/problems/add-two-numbers/solution/liang-shu-xiang-jia-by-gpe3dbjds1/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

3. 無重複字符的最長子串(滑動窗口雙指針)

用了帶剪枝的暴力法,每次維護一個set,可是最後仍是超時了算法

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        //遍歷確定不行,子串表示要連續
        //嘗試雙指針遍歷加剪枝
        if(s.empty())return 0;
        if(s.size()==1)return 1;
        int len = s.size();
        int max = 1;
        for(int i= 0 ; i<len ; i++)
        {
            set<int> st;
            st.insert(s[i]);
            for(int j = i+1; j<len ;j++)
            {
                int k = st.size();
                st.insert(s[j]);
                if(st.size()==k) break;
                if(st.size()>max)max=st.size();
            }
        }
        return max;
    }
};

對於字符串的題,最容易出現的就是超時,而這是更好的辦法每每是哈希表法docker

class Solution
{
public:
    int lengthOfLongestSubstring(string s)
    {
        //s[start,end) 前面包含 後面不包含
        int start(0), end(0), length(0), result(0);
        int sSize = int(s.size());
        unordered_map<char, int> hash;
        while (end < sSize)
        {
            char tmpChar = s[end];
            //僅當s[start,end) 中存在s[end]時更新start
            if (hash.find(tmpChar) != hash.end() && hash[tmpChar] >= start)
            {
                start = hash[tmpChar] + 1;
                length = end - start;
            }
            hash[tmpChar] = end;

            end++;
            length++;
            result = max(result, length);
        }
        return result;
    }
};

做者:pinku-2
連接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-cshi-xian-/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

雙指針法可使用滑動窗口法,每次要找到是哪裏多出來了,再從這個地方開始數組

class Solution
{
public:
    // 在左閉右開[left,right)的字符串s中,找字符target對應的下標位置,若未找到,則返回-1
    int getThePosOfSame(int left, int right, const string& s, char target) const
    {
        for (int i = left; i < right; i++)
        {
            if (s[i] == target)
            {
                return i;
            }
        }

        return -1;
    }

    int lengthOfLongestSubstring(string s)
    {
        const int len = s.length();

        int max_len = 0;
        int i = 0;
        int j = 0;

        while (j < len)
        {
            int pos = getThePosOfSame(i, j, s, s[j]);

            if (pos == -1)
            {
                j++;
            }
            else
            {
                max_len = (j - i) > max_len ? (j - i) : max_len;

                i = pos + 1;
            }
        }

        max_len = (j - i) > max_len ? (j - i) : max_len;

        return max_len;
    }
};

做者:hui-mao-zi-2
連接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/hua-dong-chuang-kou-by-hui-mao-zi-2/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

本身的寫的滑動窗口,要特別注意對數組的維護和每次更替時i和j的值緩存

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        //遍歷確定不行,子串表示要連續
        //嘗試雙指針遍歷加剪枝
        if(s.empty())return 0;
        if(s.size()==1)return 1;
        int len = s.size();
        int max = 1;
        int i = 0;
        int j = 1;
        vector<char> temp;
        temp.push_back(s[0]);
        while(i<len && j<len)
        {
            if( find(temp.begin(),temp.end(),s[j])==temp.end() )
            {
                temp.push_back(s[j]);
                j++;
                if(temp.size()>max)max =temp.size();
            }
            else
            {
                int k = find(temp.begin(),temp.end(),s[j])-temp.begin();
                i = i+k+1;
                j=i+1;
                temp.clear();
                temp.push_back(s[i]);
            }
            
        }
        return max;
        
    }
};

中間空缺的因爲未保存丟失了,包括容器的知識,如二維數組,string、char等

6.Z 字形變換

拿到題目以後的思路:
1.每行須要創建一個容器存放值
2.可是因爲行數是題目給定的,並非常量,因此只能先創建一個二維矩陣,行數就是題目的行數
3.設置在到達邊界是當即返回,這個地方還想的不是很清楚
4.可想而知會很是複雜
官方解答:

class Solution {
public:
    string convert(string s, int numRows) {

        if (numRows == 1) return s;

        vector<string> rows(min(numRows, int(s.size())));
        int curRow = 0;
        bool goingDown = false;

        for (char c : s) {
            rows[curRow] += c;
            if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown;
            curRow += goingDown ? 1 : -1;
        }

        string ret;
        for (string row : rows) ret += row;
        return ret;
    }
};

做者:LeetCode
連接:https://leetcode-cn.com/problems/zigzag-conversion/solution/z-zi-xing-bian-huan-by-leetcode/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

首先因爲是字符串型,沒必要設置char型的二維矩陣而是直接設置一維而後進行拼接就好了,其次,對於到終點就返回的一個要求,就簡單定義一個變量,從上到下時每次變量加1,從下到上每次變量鍵1,能夠設置一個bool開關,做爲加一和減一的標誌,以前想的堆棧什麼都太複雜了,雖然容器好用,可是能用一維的就不用二維,能用一兩個指針或者變量的就不用堆棧

7.整數反轉

class Solution {
public:
    int reverse(int x) {
        int p = 10;
        int n;
        long result = 0;
        if(x == INT_MIN)
        {
            return 0;
        }
        if (x >= 0)
        {
            
            while(x > 0)
            {
                n = x % p;
                x = x / p;
                result = result*10 + n;
            }
            if(result > INT_MAX)
            {
                return 0;
            }
            return result;

        }
        else
        {
            int y = -x;
            while(y > 0)
            {
                n = y % p;
                y = y / p;
                result = result*10 + n;
            }
            if(result > INT_MAX)
            {
                return 0;
            }
            return -result;
        }
    }
};

幾點說明:
1.INT_MIN ,INT_MAX第一次見
INT_MAX = 2^31-1
INT_MIN= -2^31
另外爲了防止result直接溢出了先試用long類型(8字節)進行定義!
2.反轉後不用放到容器裏而是分離的時候能夠直接構成反轉數;
3.遇到正反兩種狀況時不須要分兩大類,而是在開頭轉換就能夠,使用一次遞歸,以下所示

class Solution
{
public:
    int reverse(int x)
    {
        long result(0); //利用long避免溢出
        if (x == INT_MIN)
        {
            return 0;
        }
        if (x < 0)
        {
            return -reverse(-x);//當x小於0,再次調用該函數解出x大於0的狀況,結果加負號返回
        }

        int digit(0);
        while (x > 0)
        {
            digit = x % 10;
            x /= 10;
            result = result * 10 + digit;//這裏能夠直接返回
        }

        if (result > INT_MAX)
        {
            return 0;
        }
        return int(result);
    }
};

做者:pinku-2
連接:https://leetcode-cn.com/problems/reverse-integer/solution/zheng-shu-fan-zhuan-cshi-xian-liang-chong-jie-fa-z/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
class Solution {
public:
    int reverse(int x) {
        int rev = 0;
        while (x != 0) {
            int pop = x % 10;
            x /= 10;
            if (rev > INT_MAX/10 || (rev == INT_MAX / 10 && pop > 7)) return 0;
            if (rev < INT_MIN/10 || (rev == INT_MIN / 10 && pop < -8)) return 0;
            rev = rev * 10 + pop;
        }
        return rev;
    }
};

做者:LeetCode
連接:https://leetcode-cn.com/problems/reverse-integer/solution/zheng-shu-fan-zhuan-by-leetcode/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

9.迴文數

這裏使用了整數反轉的思路,直接比對反轉後是否相等就知道是不是迴文數;
另外,爲了防止超範圍,result可使用類型long;
另外,數字和字符串轉換不如算法方式好;

class Solution {
public:
    bool isPalindrome(int x) {
        if(x < 0){return false;}
        else
        {
            long result = 0;
            int y = x;
            int n = 0;
            while(x > 0)
            {
                n = x % 10;
                x = x / 10;
                result = result*10 + n;
            }
            if (result == y){return true;}
            else{return false;}
        }
    }
};

看到一種新寫法

return (x==n) ? true : false;

可代替原來的代碼爲

return (result == y) ? true: false;

13.羅馬數字轉換

這則代碼在map的使用上花費了較多時間,s是string字符串,s[0]能夠去除字符串的第一個元素,可是必定不能使用luoma[「s[0]」]去提取值,由於s[0]這裏不會進行編譯的!因此要提取的話要找自己就是string類型的,而s.substr(n,m)能夠作到這一點,n表明起始位置,m表明提取的個數,將其放入luoma[]中能夠提取到想要的value。

#include <map>
#include <iostream>
using namespace std;
class Solution {
public:
    int romanToInt(string s) {
        int length = s.size();
        std::map<string,int> luoma;
        luoma.insert(pair<string,int>("I",1));
        luoma.insert(pair<string,int>("V",5));
        luoma.insert(pair<string,int>("X",10));
        luoma.insert(pair<string,int>("L",50));
        luoma.insert(pair<string,int>("C",100));
        luoma.insert(pair<string,int>("D",500));
        luoma.insert(pair<string,int>("M",1000));
        long result = 0;
        if (length >1)
        {
            for (int i = 0;i < length-1; i++ )
            {
                if(luoma[s.substr(i,1)] >= luoma[s.substr(i+1,1)])
                {
                    result = result + luoma[s.substr(i,1)];   
                }
                else 
                {
                    result = result - luoma[s.substr(i,1)];
                }
            }
            result = result + luoma[s.substr(length-1,1)];           
        }
        else{
           result = luoma[s.substr(0)]; 
        }

        
        return result;

    }
};

官方的

class Solution {
public:
    int romanToInt(string s) {
        unordered_map<string, int> m = {{"I", 1}, {"IV", 3}, {"IX", 8}, {"V", 5}, {"X", 10}, {"XL", 30}, {"XC", 80}, {"L", 50}, {"C", 100}, {"CD", 300}, {"CM", 800}, {"D", 500}, {"M", 1000}};
        int r = m[s.substr(0, 1)];
        for(int i=1; i<s.size(); ++i){
            string two = s.substr(i-1, 2);
            string one = s.substr(i, 1);
            r += m[two] ? m[two] : m[one];
        }
        return r;
    }
};

做者:QQqun902025048
連接:https://leetcode-cn.com/problems/roman-to-integer/solution/2-xing-python-on-by-knifezhu/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

map:

優勢:

有序性,這是map結構最大的優勢,其元素的有序性在不少應用中都會簡化不少的操做
紅黑樹,內部實現一個紅黑書使得map的不少操做在lgn的時間複雜度下就能夠實現,所以效率很是的高
缺點: 空間佔用率高,由於map內部實現了紅黑樹,雖然提升了運行效率,可是由於每個節點都須要額外保存父節點、孩子節點和紅/黑性質,使得每個節點都佔用大量的空間

適用處:對於那些有順序要求的問題,用map會更高效一些

unordered_map:

優勢: 由於內部實現了哈希表,所以其查找速度很是的快
缺點: 哈希表的創建比較耗費時間
適用處:對於查找問題,unordered_map會更加高效一些,所以遇到查找問題,常會考慮一下用unordered_map

14.最長公共前綴

整體來講思路難度不大,
1.要注意函數可能沒有返回值的狀況
2.要求一個公共最小長度,不必定非要建出容器而後求最小值,能夠直接在求每一個值的時候順帶求出最小值
3.substr函數仍是很好用的,主要是還能指定輸出的個數

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        int a = strs.size();


        if (a == 0)
        {
            return "";
        }
        else if (a == 1)
        {
            return strs[0];
        }
        else
        {
            int aamin = strs[0].size();
            for(int i = 1; i <a ; i++)
            {
                if(aamin > strs[i].size()){aamin = strs[i].size();}
            }            
            
            for (int i = 0; i < aamin; i++ )
            {
                for (int j = 0; j< a; j++)
                {
                    if (strs[0].substr(i,1) != strs[j].substr(i,1))
                    {
                        return strs[0].substr(0,i);
                    }
                }
            
            }
            return strs[0].substr(0,aamin);
            
        }
    }
};

基本同樣,不過其並無使用substr函數

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.size()==0)
            return "";
        string str="";
        int min_lenth=strs[0].size();
        for(int i=1;i<strs.size();i++)
        {
            if(min_lenth>=strs[i].size())
                min_lenth=strs[i].size();
        }
        for(int k=0;k<min_lenth;k++)    
        {
            char s=strs[0][k];
            for(int j=1;j<strs.size();j++)
            {
                if(s!=strs[j][k])
                    return str;
            }
            str+=s;
        }
        return str;
    }
};

15. 三數之和(雙指針)

直接暴力法,必定是不可取的

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        //沒有好的辦法,雙指針不行,矩陣不行,貪心不行
        //二維數組
        
        int len = nums.size();
        //vector<vector<int> > myvec(len, vector<int>(nums,0));
        set<multiset<int> > res;
        for (int i = 0; i<len; i++)
        {
            for(int j= i+1; j<len ; j++)
            {
                for (int c=j+1 ;c<len; c++)
                {
                    //if (c==i || c==j){continue;}
                    if ((nums[i]+nums[j]+nums[c])==0)
                    {
                        multiset<int> x;
                        x.insert(nums[i]);
                        x.insert(nums[j]);
                        x.insert(nums[c]);
                        res.insert(x);
                    }
                }
            }
        }
        vector<vector<int> > re;
        for(auto i:res)
        {
            vector<int> x;
            for(auto j:i)
            {
                x.push_back(j);
            }
            re.push_back(x);
        }
        //vector<vector<int> > re = res;
        return re;
        
        
    }
};

再暴力法上加了剪枝,可是仍是超時了,說明這種方法是不行的

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int len = nums.size();
        if(len<3)return {};
        sort(nums.begin(),nums.end());
        int i = 0 ;
        int j = 1 ;
        int l = 2;
        
        set<vector<int>> res;
        for(int i = 0 ; i<len ;i++)
        {
            if(nums[i]>0) break;//直接中止循環
            if(nums[i]+nums[len-2]+nums[len-1]<0)continue;//直接跳過這次循環
            for(int j = i+1;j<len ;j++)
            {
                if(nums[i]+nums[j]+nums[len-1]<0)continue;//跳過這次循環
                for(int k = j+1 ; k<len ;k++)
                {
                    if(nums[i]+nums[j]+nums[k]==0)
                    {
                        vector<int> temp = {nums[i],nums[j],nums[k]};
                        res.insert(temp);
                        //爲了防止又相同值這裏不能中止
                    }
                    if(nums[i]+nums[j]+nums[k]>0) break;//後面的k也都不行了
                }
            }

        }
        vector<vector<int>> r(res.begin(),res.end());
        return r;

        
    }
};

正確的作法,雙指針法,一個在前一個在後,尋找0-nums[i]的兩個值,特別適用於已經排序的數組,要記住排序以後數組常用 一前一後的雙指針法

class Solution
{
public:
    vector<vector<int>> threeSum(vector<int> &nums)
    {
        vector<vector<int>> result;
        int vecSize = int(nums.size());
        if (vecSize <= 2)
        {
            return result;
        }
        int possibleSize = vecSize - 2;
        sort(nums.begin(), nums.end());

        for (int index = 0; index < possibleSize; index++)
        {
            int intNow = nums[index];
            if(intNow > 0){
                break;
            }
            int negativeNow = 0 - intNow;
            int lo = index + 1;
            int hi = vecSize - 1;
            while (lo < hi)
            {
                int intLo = nums[lo];
                int intHi = nums[hi];

                if (intLo + intHi == negativeNow)
                {
                    vector<int> tmpVec{intNow, intLo, intHi};
                    result.push_back(tmpVec);
                    //去重
                    while (lo < hi && nums[lo] == intLo)
                    {
                        lo++;
                    }
                    while (lo < hi && nums[hi] == intHi)
                    {
                        hi--;
                    }
                }
                else if (intLo + intHi < negativeNow)
                {
                    lo++;
                }
                else if (intLo + intHi > negativeNow)
                {
                    hi--;
                }
            }
            //去重
            while (index + 1 < possibleSize && nums[index] == nums[index + 1])
            {
                index++;
            }
        }

        return result;
    }
};

做者:pinku-2
連接:https://leetcode-cn.com/problems/3sum/solution/san-shu-zhi-he-cshi-xian-shuang-zhi-zhen-fa-tu-shi/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

本身寫的,勉強不超時,考慮多是去重那裏費了比較多功夫

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        int len = nums.size();
        int k=0, i=1,j = len-1;
        sort(nums.begin(),nums.end());
        vector<vector<int>> res;
        while(k<=len-3)
        {
            if(nums[k]+nums[k+1]+nums[k+2]>0)break;
            if(nums[k]+nums[k+1]+nums[k+2]==0)
            {       vector<int> temp={nums[k],nums[k+1],nums[k+2]};
                    res.push_back(temp);break;};
            //if(nums[k]+nums[i]+nums[j]>0){k++;i=k+1;j=len-1;continue;}
            if(nums[k]+nums[j-1]+nums[j]<0){k++;i=k+1;j=len-1;continue;}
            while(i<j)
            {
                if(nums[i]+nums[j]==-nums[k])
                {
                    vector<int> temp={nums[k],nums[i],nums[j]};
                    res.push_back(temp);
                    i++;j--;
                }
                else if(nums[i]+nums[j]>-nums[k])
                {
                    j--;
                }
                else
                {
                    i++;
                }
            }
            k++;
            i=k+1;
            j=len-1;
        }
        set<vector<int>> r(res.begin(),res.end());
        res.assign(r.begin(),r.end());
        return res;
    }
};

16. 最接近的三數之和

class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int len = nums.size();
        int k=0,i=1,j=len-1;
        sort(nums.begin(),nums.end());
        int res = 1e6;
        if(nums[0]+nums[1]+nums[2]>target) return nums[0]+nums[1]+nums[2];
        if(nums[len-3]+nums[len-2]+nums[len-1]<target) return nums[len-3]+nums[len-2]+nums[len-1];
        while(k<=len-3)
        {
            if(nums[k]+nums[k+1]+nums[k+2]>target)
            return abs(res-target)<abs(nums[k]+nums[k+1]+nums[k+2]-target)?res:nums[k]+nums[k+1]+nums[k+2];
            while(i<j)
            {
                if(nums[k]+nums[i]+nums[j]==target)return target;
                else if(nums[k]+nums[i]+nums[j]>target)
                {
                    res = abs(res-target)<abs(nums[k]+nums[i]+nums[j]-target)?res:nums[k]+nums[i]+nums[j];j--;
                }
                else
                {
                    res =abs(res-target)<abs(nums[k]+nums[i]+nums[j]-target)?res:nums[k]+nums[i]+nums[j];i++;
                }
            }
            k++;
            i=k+1;
            j=len-1;
        }
        return res;
    }
};

17. 電話號碼的字母組合

怎麼排列出全部的狀況,時最難的地方

string str;
	str = str + 'm' + "m" + to_string(m)+char(m) + char(m+'0') ;

字符串拼接,加號也行,單雙引號都能拼,整型用to_string
這題能使用遞歸,可是很差理解,這個隊列的思想很是實用,很是像二叉樹層序遍歷的過程!先遍歷第一曾(單個的),每個生成一個組合再放到隊列末尾,而這個彈出,像極了把子節點放入隊列後面,而後將此節點彈出的過程
隊列是有效的一種遍歷手段

class Solution {
public:
	vector<string> letterCombinations(string digits) {
		vector<string> res;//用於輸出向量
		map<char, string> m = { {'2',"abc" },{'3',"def"},{'4',"ghi"},{'5',"jkl"},{'6',"mno"},{'7',"pqrs"},{'8',"tuv"},{'9',"wxyz"} };//映射map哈希表
		int size = digits.size();//輸入字符串產長度
		queue<string> que;//新建隊列
		
		//先將第一個元素對應的碼錶入隊
		for (int j = 0; j < m[digits[0]].size(); j++)
		{
			string str;
			str.push_back(m[digits[0]][j]);//char轉string
			que.push(str);//string入隊,分別將'a','b','c'入隊列
		}
		string s;//用於存儲隊頭元素
		for (int i = 1; i < size; i++)//對剩下的第二個開始進行遍歷,每一都會組成新的字符串放入隊列,而後將此彈出
		{
			int length = que.size();//當前隊列長度,這時的隊列存放的是上一層全部的字符串,以前的都彈掉了,對於裏面的每一個,都須要新的組合進入隊尾,再彈出這個
			while (length--)//
			{
				for (int j = 0; j < m[digits[i]].size(); j++)
				{
					s = que.front();
					s = s + m[digits[i]][j];//隊頭元素加上新元素
					que.push(s);//入隊
				}
				que.pop();//隊頭出隊
			}
		}
		while (!que.empty())
		{
			res.push_back(que.front());//隊頭元素存儲至res
			que.pop();//隊頭出隊
		}
		return res;//返回
	}
};

做者:su-ge
連接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/solution/c-dui-lie-jian-dan-shi-xian-yi-dong-by-su-ge/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

套用遞歸模板能夠寫出遞歸

class Solution {
private:
vector<string> res;
string path;
int len;
public:
    void dfs(unordered_map<char,string> mymap, int pos, string digits)
    {
        if(pos == len)
        {
            res.push_back(path);
        }
        for(auto i:mymap[digits[pos]])
        {
            path = path+ i;
            dfs(mymap,pos+1,digits);
            path.pop_back();
        }
    }

    vector<string> letterCombinations(string digits) {
        if(digits.empty())return res;
        len = digits.size();
        unordered_map<char,string> mymap{{'2',"abc"},{'3',"def"},{'4',"ghi"},{'5',"jkl"},{'6',"mno"},{'7',"pqrs"},{'8',"tuv"},{'9',"wxyz"}};
        dfs(mymap,0,digits);
        return res;
    }
};

18. 四數之和

借鑑以前三數之和的雙指針法,能作可是計算量大

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(),nums.end());
        int len = nums.size();
        int i = 0, j = 1, k1= 2,k2= len-1;
        set<vector<int> > res;
        while(i< len-3  )
        {
            while(j<len-2)
            {
                while( k1<k2)
                {
                    int temp = nums[i]+nums[j]+nums[k1]+nums[k2];
                    if (temp == target)
                    {
                        vector<int> vec ={nums[i], nums[j], nums[k1],nums[k2]};
                        res.insert(vec); 
                        k1++; 
                    }
                    else if (temp > target){k2--;}
                    else {k1++;}
                }
                j++;
                k1 = j+1;
                k2 = len-1;
            }
            i++;
            j=i+1;
            k1=j+1;
            k2=len-1;
        }
        vector<vector<int> > re;
        for (auto i :res)
        {
            re.push_back(i);
        }
        return re;
    }
};

這樣的方法可行,在這個方法上能夠有更優化的辦法,以前有特殊狀況0,因此即判斷第一個指針值的大小和0的關係就好了,可是當target不爲0時不能這樣簡單的判斷,由於0如下的值越加越小,0以上的值越加越大,因此能夠換個稍微複雜的驗證方式,假設頭節點是p,若是p和右邊的三個的和都大於target,就不必了,能夠中止循環,由於還會大於target,若是p和最後三位的加和還小於target的話,那麼就說明這個p不可能組成,直接計算p+1的狀況

指針依次是 p,k,i,j,若是 nums[p] + 3 * nums[p + 1] > target,由於 nums 按升序排列,因此以後的數確定都大於 target ,直接 break;

若是 nums[p] + 3 * nums[-1] < target,那麼當前的 nums[p] 加其他三個數必定小於 target,故 p 直接下一位便可,continue;

做者:z1m
連接:https://leetcode-cn.com/problems/4sum/solution/shuang-zhi-zhen-gao-su-jie-fa-by-ml-zimingmeng/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

第二次寫的加入剪枝的操做

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        int len = nums.size();
        int k=0,l=1,i=2,j=len-1;
        sort(nums.begin(),nums.end());
        set<vector<int>> res;
        while(k<=len-4)
        {
            if(nums[k]+nums[k+1]+nums[k+2]+nums[k+3]>target)break;
            if(nums[k]+nums[j-2]+nums[j-1]+nums[j]<target){k++;l=k+1;i=k+2;j=len-1;continue;}
            while(l<=len-3)
            {
                if(nums[k]+nums[l]+nums[l+1]+nums[l+2]>target)break;
                if(nums[k]+nums[l]+nums[j-1]+nums[j]<target){l++;i=l+1;j=len-1;continue;}
                while(i<j)
                {
                    if(nums[k]+nums[l]+nums[i]+nums[j]==target)
                    {
                        vector<int> temp={nums[k],nums[l],nums[i],nums[j]};
                        res.insert(temp);i++;j--;
                    }
                    else if(nums[k]+nums[l]+nums[i]+nums[j]>target)
                    {
                        j--;
                    }
                    else
                    {
                        i++;
                    }
                }
                l++;i=l+1;j=len-1;
            }
            k++;
            l=k+1;
            i=l+1;
            j=len-1;
        }
        vector<vector<int>> r(res.begin(),res.end());
        return r;
    }
};

19. 刪除鏈表的倒數第N個節點

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        
        int len=0;
        ListNode* temp = head;
        while(temp!=nullptr)
        {
            len++;
            temp = temp->next;
        }
        if(len==1){return NULL;}
        else if (len==n){head = head->next;}
        else 
        {
            temp =head;
            for(int i= 0;i<len-n-1;i++)
            {
                temp=temp->next;
            }
            
            temp ->next = temp ->next->next;
        }
        return head;
    }
};

思想是找到該節點的前一個節點,可是要注意特殊狀況,即刪除的是第一個節點的狀況,這種狀況下會沒有前一個節點

雙指針,當快的前進n時,慢的開始;當快的到結尾時,慢的正好到能夠刪除的那個節點前一個,對於一維方向上的問題,雙指針能夠解決絕大數

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {   
        ListNode* dummy = new ListNode(NULL);
        dummy->next = head;  //添加頭節點,便於操做
        ListNode* slow=dummy,* fast=dummy;
        int distance=0;
        while(fast->next){
            if(distance<n){
                fast=fast->next;
                distance++;
            }else{
                fast=fast->next;
                slow=slow->next;
            }
        }
        slow->next=slow->next->next;
        return dummy->next;
    }
};

做者:zgdgod
連接:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/solution/c-by-zgdgod-4/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

20.有效的括號(堆棧的運用)

有效運用了break和continue:一個是當即退出當前循環,一個是結束本次循環;

class Solution {
public:
    bool isValid(string s) {
        int length = s.size();
        if (length % 2 == 1)
        {
            return false;
        }
        else
        {
            map <string ,int> fuhao = {{"(",1}, {")",-1}, {"[",2}, {"]",-2}, {"{",3}, {"}",-3}};
            while((s.size()) > 0)
            {
                
                length = s.size();
                for(int i = 0; i < s.size()-1; i++)
                {
                    if ( fuhao[s.substr(i,1)] == - fuhao[s.substr(i+1,1)])
                    {
                        s.erase(i,2);
                        break;
                    }
                }
                if(length == 0)
                {
                    return true;
                }
                else if (length == s.size())
                {           
                    return false;
                }
                else
                {
                    continue;
                }

            }
            return (s.size() == 0) ? (true) : (false);
        }
    }
    

};

思路:對於字符串s
若下一個字符是左括號:則任務數量task+1,且將須要匹配的右括號數字添加至key容器;
若下一個字符是右括號:
一、如果key容器中最後一個數字對應的右括號,則任務數量task-1,移除容器最後一項;
二、若不是key容器中最後一個數字對應的右括號,則直接結束,返回False。

知識點:
1.for(auto i : s)遍歷s中的全部字符、元素,甚至可使用自動類型推斷,一個冒號就解決了,實用性很大!
2.vector.empty()與
if (vector.size() == 0 ){return true}
else {return false} 的效果更簡潔,若是要反着來能夠在前面加一個!
3.對於s中的每個符號,若是是左半邊,就把這個推動容器;若是是右半邊,此時若容器爲空則說明以前沒有左半邊入棧,則false,若是容器不爲空繼續,把容器最後一個左半括號提取出來,若是此右半邊和這個括號不匹配,則false,若是匹配則彈出此左半括號,繼續下去,所有走完後,直接用空就表明是否所有匹配,一語雙關!

class Solution {
public:
    bool isValid(string s) {
        if(s.size() % 2) return false;
        vector<char> vecStack;//字符型的容器
        char c;
        //對於s中的每個符號,若是是左半邊,就把這個推動容器;若是是右半邊,此時若容器爲空則說明以前沒有左半邊入棧,則false,若是容器不爲空繼續,把容器最後一個左半括號提取出來,若是此右半邊和這個括號不匹配,則false,若是匹配則彈出此左半括號,繼續下去,所有走完後,直接用空就表明是否所有匹配,一語雙關!
        for(auto i : s) { 
            if(i == '}' || i == ')' || i== ']') {
                if (!vecStack.empty()) c = vecStack[vecStack.size()-1];
                else return false;
                if(i == '}' && c != '{') return false;
                if(i == ')' && c != '(') return false;
                if(i == ']' && c != '[') return false;
                vecStack.pop_back();
            }
            else vecStack.push_back(i);
        }
        return vecStack.empty();
    }
};

做者:wallcwr
連接:https://leetcode-cn.com/problems/valid-parentheses/solution/jing-dian-jian-dan-de-zhan-wen-ti-by-wallcwr/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

本身又寫了一遍,發現一個問題:必須是單引號才行,雙引號就不行——單引號字符,雙引號字符串

class Solution {
public:
    bool isValid(string s) {
        vector <char> kuohao;
        if (s.size() % 2 == 1) return false;
        for (auto str : s)
        {
            if ((str == '{') || (str == '[') || (str == '('))
            {
                kuohao.push_back(str);
            }
            else
            {
                if(kuohao.size() == 0) return false;
                if (str == '}' && kuohao[kuohao.size()-1] == '{') 
                {
                    kuohao.pop_back();
                    continue;
                }
                else if (str == ']' && kuohao[kuohao.size()-1] == '[') 
                {
                    kuohao.pop_back();
                    continue;
                }
                else if (str == ')' && kuohao[kuohao.size()-1] == '(' )
                {
                    kuohao.pop_back();
                    continue;
                }                                
                else
                {
                    return false;
                }
            }
        }
        return kuohao.empty();
    }
};

在C++中單引號表示字符,雙引號表示字符串。

例如 :在定義一個數組的時候string a [5]={「nihao」,「henhao」,「good」,「en」,「h」};

定義的是一個字符串數組,這是字符串元素要用雙引號。

char b[5]={‘a’,‘b’,‘c’,‘d’,‘e’};

定義的是一個字符數組,元素要用單引號。

要注意元素的輸出不一樣:

int a=10;

cout<<「a」;輸出爲 字符a;這就是上次「s[0]」中不能再編譯s[0]的緣由,可是若是是單引號沒準能編譯

cout<<a;輸出爲10;

cout<<‘a’ ;輸出爲65;

21.合併鏈表

思路正確,但就是代碼有些複雜

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        ListNode* head = new ListNode(0);
        ListNode* res = head;
        ListNode* temp1 = l1;
        ListNode* temp2 = l2;
        while(temp1!= nullptr && temp2!= nullptr)
        {
            while (temp1 != nullptr && temp1->val <= temp2->val)
            {
                ListNode* temp = new ListNode(temp1->val);
                res->next = temp;
                res = temp; 
                temp1 = temp1->next;
            }
            while (temp1 != nullptr&&temp2 != nullptr && temp1->val > temp2->val)
            {
                ListNode* temp = new ListNode(temp2->val);
                res->next = temp;
                res = temp;
                temp2 = temp2->next;
            }
        }
        while (temp1!=nullptr)
        {
            ListNode* temp = new ListNode(temp1->val);
            res->next = temp;
            res= temp;
            temp1=temp1->next;
        }
        while(temp2!=nullptr)
        {
            ListNode* temp = new ListNode(temp2->val);
            res->next =temp;
            res= temp;
            temp2=temp2->next;
        }
        return head->next;
    }
};
#include <vector>
using namespace std;

/** * Definition for singly-linked list. */

struct ListNode//鏈表的結構體
{
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

class Solution
{
public:
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
    {
        ListNode *result = new ListNode(-1); //啞節點簡化代碼
        ListNode *workNode = result;
        while (l1 != nullptr && l2 != nullptr) //直到有一個爲空指針爲止
        {
            if (l1->val <= l2->val) //若是1的值小於2的值,就考察1的下一個值
            {
                workNode->next = l1;
                l1 = l1->next;
            }
            else//考察2的下一個值
            {
                workNode->next = l2;
                l2 = l2->next;
            }
            workNode = workNode->next;
        }
        workNode->next = (l1 != nullptr) ? l1 : l2;//誰不爲空就把誰剩下的加進去

        return result->next;
    }
};


連接:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-

22. 括號生成

借鑑了以前電話號碼題的思路,經過一個隊列作到了層序遍歷,可是因爲產生的括號的有效性不能保證,因此又寫了一個判斷有效性的函數,過程十分複雜

class Solution {
public:
    bool isright(string s)
    {
        stack<char> st;
        for (auto i : s)
        {
            if (i == '(') { st.push('('); }
            else
            {
                if (!st.empty() && st.top() == '(') { st.pop(); }
                else { return false; }
            }
        }
        if (st.empty()) { return true; }
        else { return false; }
    }

    vector<string> generateParenthesis(int n) {
        if (n == 0)
        {
            vector<string> s = { "" };
            return s;
        }
        else
        {
            string s = "(";
            queue<string> res;
            res.push(s);
            for (int i = 0; i < 2 * (n-1); i++)
            {
                int j = res.size();
                while (j)
                {

                    string s1 = res.front() + "(";
                    res.push(s1);
                    string s2 = res.front() + ")";
                    res.push(s2);
                    res.pop();
                    j--;
                }
            }
            vector<string> re;
            while (!res.empty())
            {
                string s3 = res.front() + ")";
                if (isright(s3))
                {
                    re.push_back(s3);
                    res.pop();
                }
                else { res.pop(); }
            }
            return re;
        }



    }
};

有一種能大大提升效率的方法(多用於樹形問題)是剪枝算法,及時判斷是否可行,不可行就捨去這一樹枝

遞歸作法(代碼簡單可是情景必需要知足遞歸條件):

class Solution {
public:
	vector<string> generateParenthesis(int n) {
		if (n == 0)  return{ "" };
		if (n == 1)  return{ "()" };
		vector<string> ans;
		generateParenthesisIter("(", n-1, n, ans);
		return ans;
	}

	void generateParenthesisIter(string valid, int left_num, int right_num, vector<string>& ans){
		if (left_num == 0){     //遞歸終止條件
			valid.append(right_num, ')');
			ans.push_back(valid);
			return;
		}
		for (int n = left_num; n >= 0; n--){ //本層使用的左括號數量
			string str = valid;
			if (left_num - n > right_num - 1)//剪枝: 無效的分支 
				return; //剩餘括號中左括號數量大於右括號數量,說明已用的右括號數量大於左括號數量
			str.append(n, '(');
			str.append(1, ')');
			generateParenthesisIter(str, left_num - n, right_num - 1, ans);
		}
		return;
	}
};

做者:lcl-17
連接:https://leetcode-cn.com/problems/generate-parentheses/solution/c-shen-du-you-xian-bian-li-0ms-by-lcl-17/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

找到全部括號的組合方式看起來比較複雜。
因此咱們能夠嘗試換個思路:若是「(」對應數字1,「)」對應數字-1呢?
經過觀察咱們能夠發現這樣一個規律:
凡有效的括號組合,轉化成數字,任意前n項和都不小於0!
好比:「()()()」
前1位:1>=0;前2位:1+(-1)=0>=0;前3位:1+(-1)+1=1>=0;
…以此類推,前n位數字和均大於等於0.
又好比:「((()))」
前3位:1+1+1=3>=0;前4位:1+1+1+(-1)=2>=0;前5位:1+1+1+(-1)+(-1)=1>=0;
…依然知足規律。
至此,咱們就能想到這樣一個思路:
1.目標爲n時,能夠轉化爲n個-1和n個1
2.求這串數字的全部排列
3.知足以上規律的就是有效的括號組合
4.最後一步再將數字組合轉化成括號組合

整個過程須要一些小的工具:
1.求全排列的函數:next_permutation
2.數字轉化成括號:容器map

class Solution {
public:
    vector<string> generateParenthesis(int n)
    {
        vector<string> result;
        if(n == 0){return result;}
        vector<vector<int>> mid;
        vector<int> temp;
        for(int i = 0 ; i < n ; i ++)
        {
            temp.push_back(-1); //先放全部的-1
        }
        for(int i = 0 ; i < n ; i ++)
        {
            temp.push_back(1);  //再放全部的+1(這樣的緣由是由於全排列須要從小到大的順序)
        }
        while(next_permutation(temp.begin(),temp.end()))    //求全排列
        {
            int target = 0;
            int judg = 1;
            for(auto i:temp)
            {
                target+=i;
                if(target < 0)
                {
                    judg = 0;break; //是否知足前n項之和不小於0
                }
            }
            if(judg == 1){mid.push_back(temp);}//若是不用剪枝,則能夠將數組放入mid
        }
        map<int,string> invert;
        invert.insert(map<int,string>::value_type(1,"("));  //1對應左括號
        invert.insert(map<int,string>::value_type(-1,")")); //-1對應右括號
        for(auto i:mid)
        {
            string s;
            for(auto j:i)
            {
                s += invert[j]; //數字組合轉化成字符串
            }
            result.push_back(s);
        }
        return result;
    }
};

做者:da-lian-mao-ai-chi-yu
連接:https://leetcode-cn.com/problems/generate-parentheses/solution/gua-hao-tai-fu-za-shu-zi-zhuan-hua-ta-by-da-lian-m/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

全排列函數next_permutation

用這個函數一會兒就省去了找全部可能的排列,在排列以後再轉成括號就好了,因爲只有一種括號,就用1和-1來代替並使用剪枝算法

while(next_permutation(temp.begin(),temp.end())) 
 {}

next_permutation(num,num+n)函數是對數組num中的前n個元素進行全排列,同時並改變num數組的值。

另外,須要強調的是,next_permutation()在使用前須要對欲排列數組按升序排序,不然只能找出該序列以後的全排列數。

23. 合併K個排序鏈表

這種思路太好了,放到一塊兒再重構,只要掌握好新建鏈表的方法就能夠了,必須用new

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        vector<int> v;
        for(auto head:lists)
        {
            while(head)
            {
                v.push_back(head->val);
                head=head->next;
            }

        }
        sort(v.begin(),v.end());
        ListNode* head = new ListNode(0);
        ListNode* res = head;
        //int i = v.size();
        for(int i = 0 ; i<v.size(); i++)
        {
            ListNode* temp =new ListNode(v[i]);
            res->next = temp;
            res = temp; 
        }
        return head->next;
    }
};

26. 刪除排序數組中的重複項

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        
        int i =1;
        int j = 0;
        int len = nums.size();
        if(len==0)return 0;
        for(i=1; i<len;i++)
        {
            if(nums[i]==nums[j])continue;
            else
            {
                nums[++j] = nums[i];
            }
        }
        return j+1;
    }
};

27. 移除元素

循環這裏必須加等號

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
       int i = 0 ; 
       int j = nums.size()-1;
       while(i<=j)
       {
           while(i<=j && nums[i]!=val) i++;
           while(i<=j && nums[j]==val)j--;
           if(i<=j) swap(nums[i],nums[j]);
       } 
       return i;
    }
};

31. 下一個排列

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        if(next_permutation(nums.begin(),nums.end()))
        {
            return ;
        }
        else
        {
            sort(nums.begin(),nums.end());
            return ;
        }
    }
};

採用的是遍歷判斷法,可以剪枝的地方很是有限,因此超時了

class Solution {
public:
    
    bool is(string s1)
    {
        if(s1[0]==')')return false;
        int len = s1.size();
        if(len%2!=0)return false;
        stack<char> st;
        for(auto i:s1)
        {
            if(i=='(')
            {
                st.push(i);
            }
            else
            {
                if(!st.empty() && st.top()=='(')
                {
                    st.pop();
                }
                else
                {
                    return false;
                }
            }
        }
        return st.empty();
    }    
    
    int longestValidParentheses(string s) {
        //兩種辦法,第一種雙指針窗口法,當遇到破壞結構時,從中間的地方開始起,可是可能會有一點複雜
        //遍歷判斷法,專門呢寫一個函數,第一種的複雜度確定是最低的
        if(s.empty())return 0;
        int max = 0;
        int len = s.size();
        if(len==1)return 0;
        for(int i = 0 ; i<len ;i++)
        {
            for(int j = i+1;j<len;j++)
            {
                string s1=s.substr(i,j-i+1);
                if(is(s1) && j-i+1>max)max = j-i+1;
            }
        }
        return max;
    }
};

33. 搜索旋轉排序數組

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int right = nums.size();
        int left = 0;
        while(left<right)
        {
            int mid = left + (right-left)/2;
            if(nums[mid]==target){return mid;}
            else if (nums[mid]>target)
            {
                if(target>=nums[0] || nums[mid]<nums[0]){right = mid;}
                else{left=mid+1;}
            }
            else
            {
                if(nums[mid]>=nums[0] ||target<nums[0]){left=mid+1;}
                else{right=mid;}
            }
        }
        return -1;
    }
};
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int lo = 0, hi = nums.size() - 1;
        while (lo < hi) {
            int mid = (lo + hi) / 2;
            if ((nums[0] > target) ^ (nums[0] > nums[mid]) ^ (target > nums[mid]))
                lo = mid + 1;
            else
                hi = mid;
        }
        return lo == hi && nums[lo] == target ? lo : -1;
    }
};

做者:LukeLee
連接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/ji-jian-solution-by-lukelee/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

34. 在排序數組中查找元素的第一個和最後一個位置

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        int left = 0, right = nums.size();
        while(left<right)
        {
            int mid = left + (right-left)/2;
            if(nums[mid]==target)
            {
                int t1 =mid-1, t2 = mid+1;
                while(t1>=0 && nums[t1]==target)t1--;
                while(t2<(int)nums.size() && nums[t2]==target)t2++;
                return {t1+1,t2-1};
            }
            else if(nums[mid]<target)
            {
                left = mid +1;
            }
            else{right = mid;}
        }
        return {-1,-1};
    }
};

35. 搜索插入位置(二分法***************)

二分法的邊界仍是比較難處理,這道題中當存在相等時就直接返回mid,當不相等的時候須要進行兩值夾逼併返回有值,並且兩個邊界都不能捨去,可是這樣又會可能無限循環,最後還要加個if判斷是否夾逼了

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int len = nums.size();
        int left=0,right = len-1;
        if(target<=nums[0])return 0;
        if(target>nums[len-1])return len;
        if(target==nums[len-1])return len-1;
        while(left<right)
        {
            int mid = (left+right)/2;
            if(nums[mid]==target)return mid;
            else if(nums[mid]>target)
            {
                right = mid;
            }
            else
            {
                left = mid;
            }
            if(left==right-1 && nums[left]<target && nums[right]>target )return right;
        }
        return right;
    }
};

簡單的寫法
能夠不用夾逼,由於找的時剛剛大於等於這個值的,因此每次讓左邊界加1

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int low = 0, high = nums.size() - 1, mid = 0;
        while(low <= high){
            mid = low + (high - low) / 2;
            if(nums[mid] < target) low = mid + 1;
            else if(nums[mid] > target) high = mid - 1;
            else return mid;
        }
        return low;
    }
};

比較使用的模板
用來求剛剛大於等於target的第一個值

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int len = nums.size();
        int left=0,right = len;
        while(left<right)
        {
            int mid = (left+right)/2;
            if(nums[mid]==target)return mid;
            else if(nums[mid]<target)
            {
                left = mid+1;
            }
            else
            {
                right = mid;
            }
        }
        return left;
    }
};

36. 有效的數獨

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        //主要考察二維數組用法
        //每一列
        for(int i= 0 ; i<9 ;i++)
        {
            set<char> st;
            int num = 0;
            for(int j = 0 ; j < 9; j++)
            {
                if(board[i][j]=='.'){continue;}
                else{st.insert(board[i][j]);num++;}
            }
            if(st.size()!=num){return false;}
        }
        //每行
        for(int i= 0 ; i<9 ;i++)
        {
            set<char> st;
            int num = 0;
            for(int j = 0 ; j < 9; j++)
            {
                if(board[j][i]=='.'){continue;}
                else{st.insert(board[j][i]);num++;}
            }
            if(st.size()!=num){return false;}
        }
        
        for(int c1 = 0 ; c1<9; c1=c1+3)
        {
            for(int c2 =0 ; c2<9 ;c2=c2+3)
            {
                set<char>st;
                int num=0;
                for(int i=0 ; i<3 ;i++)
                {
                    for(int j = 0; j<3; j++)
                    {
                        if(board[c1+i][c2+j]=='.'){continue;}
                        else{st.insert(board[c1+i][c2+j]);num++;}
                    }
                    
                }
                if(st.size()!=num){return false;}
            }
        } 
        
        return true;      
    }
};

36. 有效的數獨

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        vector<int> wow(9,0);
        int mux1;
        int mux2;
        int mux3;
        int box_index;

        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                if(board[i][j] == '.'){
                    continue;
                }
                mux1 = 0x01 << (board[i][j] - '1');
                mux2 = 0x01 << 9 << (board[i][j] - '1');
                mux3 = 0x01 << 9 << 9 << (board[i][j] - '1');
                box_index = (i/3) * 3 + j/3;
                if((wow[i]&mux1) != mux1 && (wow[j]&mux2) != mux2 && (wow[box_index]&mux3) != mux3){
                    wow[i] = wow[i]|mux1;
                    wow[j] = wow[j]|mux2;
                    wow[box_index] = wow[box_index]|mux3;
                }
                else{
                    return false;
                }
            }
        }
        return true;
    }
};

這個遍歷三次太複雜了,並且使用set時間也比較長
下面這個方法靈活運用了三個哈希表(二維數組實現)的,單次遍歷,用目的區域(行、列、快)來表示行,用1-9來9個數字出現次數做爲列,列爲10由於直接對應,0不算,給9加一行

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        int row[9][10] = {0};// 哈希表存儲每一行的每一個數是否出現過,默認初始狀況下,每一行每個數都沒有出現過
        // 整個board有9行,第二維的維數10是爲了讓下標有9,和數獨中的數字9對應。
        int col[9][10] = {0};// 存儲每一列的每一個數是否出現過,默認初始狀況下,每一列的每個數都沒有出現過
        int box[9][10] = {0};// 存儲每個box的每一個數是否出現過,默認初始狀況下,在每一個box中,每一個數都沒有出現過。整個board有9個box。
        for(int i=0; i<9; i++){
            for(int j = 0; j<9; j++){
                // 遍歷到第i行第j列的那個數,咱們要判斷這個數在其所在的行有沒有出現過,
                // 同時判斷這個數在其所在的列有沒有出現過
                // 同時判斷這個數在其所在的box中有沒有出現過
                if(board[i][j] == '.') continue;
                int curNumber = board[i][j]-'0';
                if(row[i][curNumber]) return false; 
                if(col[j][curNumber]) return false;
                if(box[j/3 + (i/3)*3][curNumber]) return false;

                row[i][curNumber] = 1;// 以前都沒出現過,如今出現了,就給它置爲1,下次再碰見就可以直接返回false了。
                col[j][curNumber] = 1;
                box[j/3 + (i/3)*3][curNumber] = 1;
            }
        }
        return true;
    }
};

做者:liujin-4
連接:https://leetcode-cn.com/problems/valid-sudoku/solution/36-jiu-an-zhao-cong-zuo-wang-you-cong-shang-wang-x/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

寫了一套很是複雜的算法,原理是依次判斷每一個控制區域,若是有個地方能用三個條件判斷出來則填上,而後再解決其餘的,結果發現代碼在無限循環,緣由是不存在這樣的直接能夠判斷出來的位置,這樣原理上就出錯了

class Solution {
public:
    int num(vector<vector<char>>& board, int k1, int k2)
    {

        map<char, int> m = { {'1',0},{'2',0},{'3',0},{'4',0},{'5',0},{'6',0},{'7',0},{'8',0},{'9',0} };
        for (int i = 0; i < 9; i++)
        {
            if (board[k1][i] != '.') { m[board[k1][i]] = 1; }
            if (board[i][k2] != '.') { m[board[i][k2]] = 1; }
        }
        for (int i = 0; i < 3; i++)
        {
            for (int j = 0; j < 3; j++)
            {
                if (board[k1 / 3 + i][k2 / 3 + j] != '.') { m[board[k1 / 3 + i][k2 / 3 + j]] = 1; }
            }
        }
        map<char, int>::iterator iter;
        int num = 0;
        int res = 0;
        for (auto iter = m.begin(); iter != m.end(); iter++)
        {
            //int num = 0;
            if (iter->second == 0) { res = iter->second; num++; }

        }
        if (num == 1) { return res; }
        else { return 0; }


    }


    bool is(vector<vector<char>>& board)
    {
        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                if (board[i][j] == '.') { return false; }

            }
        }
        return true;
    }
        void solveSudoku(vector<vector<char>>& board) {
        //想法使用遞歸,終止條件是填滿了,方法是對空着的位置進行遍歷,每個都設置一個哈希,當行列塊又出現的設爲1,當剩最後一個 了時就返回這個表

        for (int i = 0; i < 9; i++)
        {
            for (int j = 0; j < 9; j++)
            {
                if (board[i][j] == '.')
                {
                    if (num(board, i, j)) { board[i][j] = char(num(board, i, j)+'0' ); }
                    else { continue; }
                }
            }
        }
        while (!is(board)) { solveSudoku(board); }
        return;
    }
};

39. 組合總和

要特別注意將i放入下次dfs的寫法,目的就是爲了下次再也不查找以前的元素,值得學習

class Solution {
private:
    vector<vector<int>> res;
    vector<int> path;
    int sum = 0;
public:
    void dfs(vector<vector<int>>& res,vector<int>& candidates,vector<int>& path, int sum,int target ,int j)
    {
        if(sum == target)
        {
            res.push_back(path);return;
        }
        if(sum>target)return;
        for(int i = j; i<(int)candidates.size() ;i++)
        {
            path.push_back(candidates[i]);
            sum +=candidates[i];
            dfs(res,  candidates,  path,  sum,  target,i);
            path.pop_back();
            sum -=candidates[i];
        }
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        dfs(res,candidates,path,0,target,0);
        return res;
    }
};

dfs深度優先搜索***

回溯算法:當給定終點時,能夠進行回退
再加上遞歸和剪枝算法

二叉樹經常使用算法:回溯、隊列、遞歸、剪枝

負遞歸算法:

// author:rmokerone
#include <iostream>
#include <vector>

using namespace std;

class Solution {
private://成員變量
    vector<int> candidates;
    vector<vector<int>> res;
    vector<int> path;
public:
    void DFS(int start, int target) {
        if (target == 0) {  //遞歸終止條件
            res.push_back(path);
            return;
        }
        for (int i = start; i < candidates.size() && target - candidates[i] >= 0; i++) {
            path.push_back(candidates[i]);
            DFS(i, target - candidates[i]);
            path.pop_back();
        }
    }

    vector<vector<int>> combinationSum(vector<int> &candidates, int target) {
        std::sort(candidates.begin(), candidates.end());
        this->candidates = candidates;
        DFS(0, target);

        return res;
    }

};

做者:liweiwei1419
連接:https://leetcode-cn.com/problems/combination-sum/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-2/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

正遞歸加剪枝算法:
要特別注意幾點:
1.是用了剪枝是爲了提速
2.除此以外,在深度優先搜索的時候能夠設置從當前元素開始,由於以前的元素在以前的節點已經用過了因此加了一個start變量用來記錄在can容器中的位置
3.像sum這種的不用每次都計算,直接加個參數就好了,注意全局變量的定義位置,由於遞歸函數要用,因此定義在全局的地方,還能夠在外面定義可是在函數中進行計算,好比siz這個變量,更嚴格點能夠定義在private中

class Solution {
public:
    vector<int> tmp;
    vector<vector<int>> ans;
    int siz;

    void dfs(int now, int sum, int tar, vector<int>& num)
    {
        if(sum > tar) return;
        if(sum == tar)
        {
            ans.push_back(tmp);
            return;
        }
        for(int i = now; i < siz; i ++)
        {
            tmp.push_back(num[i]); //一層一層往下走
            dfs(i, sum + num[i], tar, num); //當大於或者等於時都會返回
            tmp.pop_back();//回到上一個分叉節點,從整個樹的最左邊一條開始試
        }
    }

    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        siz = candidates.size();
        dfs(0, 0, target, candidates);
        return ans;
    }
};

做者:iswJXkYVv3
連接:https://leetcode-cn.com/problems/combination-sum/solution/c-di-gui-shen-sou-by-iswjxkyvv3/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

41. 缺失的第一個正數

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        //sort(nums.begin(),nums.end());
        for(int i = 1;true;i++)
        {
            auto temp = find(nums.begin(),nums.end(),i);
            if (temp==nums.end()){return i;}
        }
    }
};

還可使用哈希表作,創建一個1到n的哈希表,遍歷過數組後找第一個哈希值爲0的

42. 接雨水

這是一個創建在一維數組上的問題,理論上這類的全部問題均可以用雙指針來解決,這道題的難點在於找到最大值以後的後半部分怎麼處理,怎麼去找到剩下的部分,這時候須要求最大值,使用max_element函數,可是注意返回的是一個迭代器,用法以下

#include <algorithm>
//返回迭代器
auto max = max_element(v.begin(), v.end());
//獲得最大值對應下標
int kk = max-v.begin();

當開始使用這個函數的時候想把裏面全部的索引換成迭代器指針,可是發如今執行起來十分有困難,就是由於迭代器之間不傳遞,好比i和j都是v的迭代器,i++被容許,可是j=i+1就不被容許,因此能不使用迭代器就不使用,當要使用那些返回迭代器的方法時,能夠用他減去v.begin()天然就返回的是下標位置

class Solution {
public:
    int trap(vector<int>& height) {
        if(height.size()<=2){return 0;}
        int i = 0;
        int j = 1;
        int sum = 0;
        while (i < height.size() - 2)
        {
            while (j<height.size() && height[i] > height[j]) { j++; }
            if (j == height.size()) 
            {
                auto m = max_element(height.begin()+i+1, height.end());
                j=m-height.begin(); 
            }
            sum = sum + (j - i - 1)*min(height[i], height[j]);
            for (int c = i + 1; c < j; c++)
            {
                sum = sum - height[c];
            }
            i = j;
            j = i + 1;
        }
        return sum;
    }
};

堆棧的方法,不是很好理解

直觀想法

咱們能夠不用像方法 2 那樣存儲最大高度,而是用棧來跟蹤可能儲水的最長的條形塊。使用棧就能夠在一次遍歷內完成計算。

咱們在遍歷數組時維護一個棧。若是當前的條形塊小於或等於棧頂的條形塊,咱們將條形塊的索引入棧,意思是當前的條形塊被棧中的前一個條形塊界定。若是咱們發現一個條形塊長於棧頂,咱們能夠肯定棧頂的條形塊被當前條形塊和棧的前一個條形塊界定,所以咱們能夠彈出棧頂元素而且累加答案到
\text{ans}ans 。

算法

使用棧來存儲條形塊的索引下標。 遍歷數組: 當棧非空且
\text{height}[current]>\text{height}[st.top()]height[current]>height[st.top()]
意味着棧中元素能夠被彈出。彈出棧頂元素 \text{top}top。 計算當前元素和棧頂元素的距離,準備進行填充操做
\text{distance} = \text{current} - \text{st.top}() -
1distance=current−st.top()−1 找出界定高度 \text{bounded_height} =
\min(\text{height[current]}, \text{height[st.top()]}) -
\text{height[top]}bounded_height=min(height[current],height[st.top()])−height[top]
往答案中累加積水量\text{ans} \mathrel{+}= \text{distance} \times
\text{bounded_height}ans+=distance×bounded_height 將當前索引下標入棧 將
\text{current}current 移動到下個位置

做者:LeetCode
連接:https://leetcode-cn.com/problems/trapping-rain-water/solution/jie-yu-shui-by-leetcode/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

int trap(vector<int>& height)
{
    int ans = 0, current = 0;
    stack<int> st;
    while (current < height.size()) {
        while (!st.empty() && height[current] > height[st.top()]) {
            int top = st.top();
            st.pop();
            if (st.empty())
                break;
            int distance = current - st.top() - 1;
            int bounded_height = min(height[current], height[st.top()]) - height[top];
            ans += distance * bounded_height;
        }
        st.push(current++);
    }
    return ans;
}

做者:LeetCode
連接:https://leetcode-cn.com/problems/trapping-rain-water/solution/jie-yu-shui-by-leetcode/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

43. 字符串相乘

沒有思路,原來是利用乘法的計算方式來的
在這裏插入圖片描述

class Solution {
public:
    string multiply(string num1, string num2) {
        int n1=num1.size();
        int n2=num2.size();
        string res(n1+n2,'0');
        for(int i=n2-1;i>=0;i--){
            for(int j=n1-1;j>=0;j--){
                int temp=(res[i+j+1]-'0')+(num1[j]-'0')*(num2[i]-'0');
                res[i+j+1]=temp%10+'0';//當前位
                res[i+j]+=temp/10; //前一位加上進位,res[i+j]已經初始化爲'0',加上int類型自動轉化爲char,因此此處不加'0'
            }
        }
        
//去除首位'0'
        for(int i=0;i<n1+n2;i++){
            if(res[i]!='0')
                return res.substr(i);
        }
        return "0";
       
        
    }
};

做者:carryzz
連接:https://leetcode-cn.com/problems/multiply-strings/solution/c-shu-shi-cheng-fa-dai-ma-jian-ji-you-ya-yi-dong-b/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

44. 通配符匹配

在這裏插入圖片描述

class Solution {
public:
    bool isMatch(string s, string p) {
        int n = s.size(), m = p.size();
        vector< vector<bool> > dp(n+1, vector<bool>(m+1, false)); dp[0][0] = true;

        // initialize 
        for (int i = 1; i <= m; ++ i){
            if(p[i - 1] == '*' && dp[0][i - 1]) dp[0][i] = dp[0][i - 1];
        }

        for (int i = 1; i <= n; ++ i){
            for (int j = 1; j <= m; ++ j){
                if (s[i - 1] == p[j - 1] || p[j - 1] == '?'){
                    dp[i][j] = dp[i - 1][j - 1];// ismatch, move on
                }else if (p[j - 1] == '*'){
                    bool zero, mul;// '*' act as zero, '*' act as multiple characters
                    zero = (j < m && s[i - 1] == p[j] && dp[i - 1][j - 1]) || dp[i][j - 1];
                    mul = dp[i -1][j];
                    dp[i][j] = zero || mul;
                }
            }
        }

        return dp[n][m];
    }
};

做者:wen-mu-yang
連接:https://leetcode-cn.com/problems/wildcard-matching/solution/c-dong-tai-gui-hua-yu-shuang-zhi-zhen-tan-xin-by-w/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。![在這裏插入圖片描述](https://img-blog.csdnimg.cn/20200329203606940.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MzU3OTA3OQ==,size_16,color_FFFFFF,t_70)

45. 跳躍遊戲 II

使用了遞歸算法,不斷更新起點,每更新一次跳到能跳到的最遠的地方,記錄到達終點時的步數,但在過程當中關於什麼時候記錄步數的問題很難。終於調成功後發現這樣是錯誤的,由於有時不須要全跳,尤爲是最後幾個值爲0的狀況,要是早早跳到這裏反而會到不了終點!

class Solution {

public:
	int ans=0;

	int summm(int start, vector<int> nums)
	{
		int  temp = max_element(nums.begin() + start +1, nums.begin() + start + nums[start]+1) - nums.begin();
		
		if (start + nums[start] >= temp + nums[temp]) { ans++; return start + nums[start]; }
		else { ans++; return temp ; }
		
	}
	int jump(vector<int>& nums) {
		int len = nums.size();
		//int ans = 0;
		if (len == 1) { return 0; }
		else
		{
			int start = 0;
			//if (start + nums[start] >= len) { return 1; }
			while (start<len )
			{

				if (start + nums[start] >= len-1) { return ans + 1; }
				start = summm(start, nums);
	
				
			}
			return ans;



		}
	}
};

在這裏插入圖片描述

貪心算法

看了解答,發現這種思路總體是對的,就是追求每一次能走的最大,然而以前的錯誤在於,並非比較start+nums[start]和max[start,start+len(start)]之間的最大值,應該比較的是和區間裏每個值和其值的和即i+len(i),這纔是走的最遠的方法,按照這種方法不斷更新,就能夠找到最後了
即便意思相近可是別人的表達也十分簡介

int jump(vector<int> &nums)
{
    int ans = 0;
    int start = 0;
    int end = 1;
    while (end < nums.size())
    {
        int maxPos = 0;
        for (int i = start; i < end; i++)
        {
            // 能跳到最遠的距離
            maxPos = max(maxPos, i + nums[i]); //在遍歷的過程當中不斷更新這個最大值
        }
        start = end;      // 下一次起跳點範圍開始的格子
        end = maxPos + 1; // 下一次起跳點範圍結束的格子,加一是由於上面的遍歷時左閉右開的
        ans++;            // 跳躍次數
    }
    return ans;
}

做者:ikaruga
連接:https://leetcode-cn.com/problems/jump-game-ii/solution/45-by-ikaruga/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

46. 全排列

關於全排列next_permumation有幾點須要說明
1.之氣那要排序
2.只要開始全排列,第一個結果是已經改變以後的數組,而不是原來的
3。參數是首末迭代器

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int> > res;
        sort(nums.begin(), nums.end());
        res.push_back(nums);
        while(next_permutation(nums.begin(),nums.end()))
        {
            res.push_back(nums);
        }
        return res;
        
    }
};

這是使用隊列層序遍歷的方法寫的,可是因爲不容許重複,每次要使用find判斷,十分複雜

class Solution {
public:
    vector<vector<int>> permute(vector<int>& nums) {
        vector<vector<int> > res;
        if (nums.size()==0 || nums.size()==1)
        {
            res.push_back(nums);
            return res;
        }
        sort(nums.begin(), nums.end());
        queue<vector<int>> q;
        
        for(auto i:nums)
        {
            vector<int> temp;
            temp.push_back(i);
            q.push(temp);
        }
        
        //int i=nums.size()-1;
        while(q.front().size()!=nums.size())
        {                
                
                for (auto i:nums)
                {
                    vector<int> temp = q.front();
                    if(find(temp.begin(),temp.end(),i)==temp.end())
                    {
                        temp.push_back(i);
                        q.push(temp);
                    }
                }
                q.pop();
        }
        while(!q.empty())
        {
            res.push_back(q.front());
            q.pop();
        }
        return res;
        
    }
};

回溯問題+決策樹

算法模板

遞歸{
    遞歸出口;
    for(int i = 1;i<=n;i++){
    	add(i);
    	進入遞歸;
   		remove(i);
	}
}


做者:windliang
連接:https://leetcode-cn.com/problems/unique-binary-search-trees-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-2-7/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
void backtrack(路徑,選擇列表)
{
	if(終止條件)
	{
		傳出路徑結果
		return;
	}
	for i in 選擇列表
	{
		進入該選擇
		back(路徑,選擇列表)
		退出該選擇
	}
}

這是根據該思想寫的代碼,代碼結構簡單,清晰,可是優化的很差

class Solution {
private:
    vector<vector<int> > res;
    int len;
    vector<int> path;
public:
    void backtrack(vector<int> &path, vector<int>& nums)
    {
        set<int> s(path.begin(),path.end());
        if(path.size()==len)
        {
            if (s.size()==len)
            {
                res.push_back(path);
                return;                
            }
            else
            {
                return;
            }
        }        
        for(auto i : nums)
        {
            path.push_back(i);
            backtrack(path,nums);
            path.pop_back();
        }
    }
    
    vector<vector<int>> permute(vector<int>& nums) {
        len = nums.size();
        if (nums.size()==0 || nums.size()==1)
        {
            res.push_back(nums);
            return res;
        }
        sort(nums.begin(), nums.end());
        backtrack(path,nums);
        return res;

        
    }
};

48. 旋轉圖像

將圖片沿正對角線和豎軸翻轉一下就能夠了

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int n = matrix.size();
        int m = matrix[0].size();
        
        // 對於正對角線對稱翻轉
        for (int i = 0; i < n; i++) {
            for (int j = i; j < m; j++) {
                swap(matrix[i][j], matrix[j][i]);
            }
        }
        // 豎軸鏡像操做
        for (int i = 0; i < n; i++) {
            reverse(matrix[i].begin(), matrix[i].end());
        }
    }
};

做者:happy_yuxuan
連接:https://leetcode-cn.com/problems/rotate-image/solution/leetcode48-fan-zhuan-gui-lu-by-happy_yuxuan/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

49. 字母異位詞分組

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        vector<vector<string>> res;
        vector<pair<multiset<char>,vector<string>>> st;
        for(auto str:strs)
        {
            multiset<char> temp(str.begin(),str.end());
            bool b = false;
            for(int i = 0 ;i<(int)st.size() ;i++)
            {
                
                if(st[i].first==temp)
                {
                    st[i].second.push_back(str);
                    b = true;
                    break;
                }

            }
            if(!b)
            {
                st.push_back(pair<multiset<char>,vector<string>>(temp,{str}));
            }
        }
        for(auto i:st)
        {
            vector<string> temp;
            for(auto j:i.second)
            {
                temp.push_back(j);
            }
            res.push_back(temp);
        }
        return res;
    }
};

更好的辦法:哈希表和數組聯繫,只要引入一個hash表,索引是排序後的單詞,值爲結果vector的下標,循環一遍就行了

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        vector<vector<string>> res;  
        int sub=0;  //結果vector的下標值
        string tmp; //臨時string
        unordered_map<string,int> work; //判斷排序後單詞是否存在,即字母組成是否一致
        for(auto str:strs)
        {
            tmp=str;
            sort(tmp.begin(),tmp.end());
            if(work.count(tmp))
            {
               res[work[tmp]].push_back(str);
            }
            else
            {
                vector<string> vec(1,str);
                res.push_back(vec);
                work[tmp]=sub++;
            }
        }
        return res;
    }
};

做者:rjs
連接:https://leetcode-cn.com/problems/group-anagrams/solution/c-yin-ru-hashbiao-shi-jian-32ms-ji-bai-9948-nei-cu/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

50. Pow(x, n)

暴力法

class Solution {
public:
    double myPow(double x, int n) {
        if(x==0)return 0;
        if(x==1 || n==0) return 1;
        double res=1;
        while(n>0)
        {
            res=res*x;
            n--;
        }
        while(n<0)
        {
            res = res/x;
            n++;
        }

        return res;

    }
};

遞歸法,將指數冪進行二分,十分巧妙

class Solution {
public:
    double myPow(double x, int n) {
        if (n == 0) { return 1; }
        if (n == 1) { return x; }
        if (n == -1) { return 1 / x; }
        double half = myPow(x, n / 2);
        double rest = myPow(x, n % 2);
        return rest * half * half;
    }
};

做者:frank588
連接:https://leetcode-cn.com/problems/powx-n/solution/qing-xi-jian-dan-de-dan-han-shu-di-gui-wu-lei-xing/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

51. N皇后(回溯dfs)

思路很是清晰,典型的n皇后的問題,稍微麻煩的問題是判斷是否額可以知足條件,並且注意不用在最後才檢查條件。應該在中間進行判斷,只要可以知足條件才繼續下去,這樣到最後也就知足條件了,放一個知足一個,最後就必定知足,這裏一行一行創建的會稍微簡單一點

class Solution {
    vector<vector<string>> res;//存結果
    vector<string> tmp;//存棋盤
public:
    vector<vector<string>> solveNQueens(int n) {
        string line(n,'.');//既然一行一行試,那就一行一行存
        solveNQueens(line, 0, n);//從第0行開始
        return res;
    }

private:
    //試某一行
    void solveNQueens(string& line, int row, int n)
    {
        if(tmp.size() == n)//棋盤繪製夠n行存進結果,不用繼續試了
        {
            res.push_back(tmp);
            return;
        }
        for(int i = 0; i < n; ++i)//一格一格,每格都要試
        {
            if(checkAll(row, i, n))     //符合條件了
            {
                line[i] = 'Q';          //就把當前試的這一格放皇后
                tmp.push_back(line);    //而後把這一行繪製進棋盤
                line[i] = '.';          //棋盤的下一行應該是沒有皇后的
                solveNQueens(line, row + 1, n);//去試下一行
                tmp.pop_back();         //接下來要去試下一格,剛纔繪製進去的那一行刪掉
            }
        }
    }

    //暴力檢查條件
    bool checkAll(int row, int col, int n)
    {
        for(int i = row - 1, j = col - 1; i >= 0 && j >= 0; --i,--j)//左上方
        {
            if(tmp[i][j] == 'Q')
                return false;
        }
        for(int i = row - 1; i >= 0; --i)//正上方
        {
            if(tmp[i][col] == 'Q')
                return false;
        }
        for(int i = row -1, j = col + 1; i >= 0 && j < n; --i, ++j)//右上方
        {
            if(tmp[i][j] == 'Q')
                return false;
        }
        return true;
    }
};

做者:zynflicker
連接:https://leetcode-cn.com/problems/n-queens/solution/4ms89mhui-su-fa-jian-dan-yi-dong-by-zynflicker/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

53. 最大子序和(貪心)

很典型的使用貪心算法的例題

class Solution
{
public:
    int maxSubArray(vector<int> &nums)
    {
        //相似尋找最大最小值的題目,初始值必定要定義成理論上的最小最大值
        int result = INT_MIN;
        int numsSize = int(nums.size());
        int sum = 0;
        for (int i = 0; i < numsSize; i++)
        {
            sum += nums[i];
            result = max(result, sum);
            //若是sum < 0,從新開始找子序串
            if (sum < 0)
            {
                sum = 0;
            }
        }

        return result;
    }
};

做者:pinku-2
連接:https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-cshi-xian-si-chong-jie-fa-bao-li-f/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

55. 跳躍遊戲

每次跟新一次位置,當最遠達到的地方是0,說明false,代碼用vs會出現莫名其妙的問題,可是作法應該是對的
另外因爲可能出現的請狀況太多了,在邊界的設置上出錯的地方太多了

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int left = 0;
        int len = nums.size();
        while(1)
        {
            if(left>=len-1 || left+nums[left]>=len-1)return true;
            
            int max = 0;
            int temp = 0;
            for(int i = left ; i<=len-1 &&i<=left+nums[left] ;i++)
                {
                if(i+nums[i]>max){max = i+nums[i];temp=i;}

            }
            if(max<len-1&& nums[max]==0)return false;
            left = temp;
        }
        return false;
    }
};

一樣意思但更簡潔的代碼
解題思路:
1.若是某一個做爲 起跳點 的格子能夠跳躍的距離是 3,那麼表示後面 3 個格子均可以做爲 起跳點。
2.能夠對每個能做爲 起跳點 的格子都嘗試跳一次,把 能跳到最遠的距離 不斷更新。
3.若是能夠一直跳到最後,就成功了。

做者:ikaruga
連接:https://leetcode-cn.com/problems/jump-game/solution/55-by-ikaruga/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

bool canJump(vector<int>& nums) 
{
	int k = 0;
	for (int i = 0; i < nums.size(); i++)
	{
		if (i > k) return false;//k表示到i的時候,以前全部位置能到達的最大距離,每個都走一下,可是不用考慮怎麼走的,當走到一個位置不能再更新了,就會小於下一個i
		k = max(k, i + nums[i]);
	}
	return true;
}

做者:ikaruga
連接:https://leetcode-cn.com/problems/jump-game/solution/55-by-ikaruga/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

56. 合併區間(貪心)

一樣的格式,可是改爲max了,並且維護的不是一個樹,而是先放到二維向量中的末尾

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>> res;
        if(intervals.empty())return res;
        sort(intervals.begin(),intervals.end());
        res.push_back(intervals[0]);
        for(int i = 1 ;i< (int)intervals.size() ;i++)
        {
            if(intervals[i][0]<= res.back()[1])
            {
                res.back()[1] = max(res.back()[1],intervals[i][1]);
            }
            else
            {
                res.push_back(intervals[i]);
            }
        }
        return res;
    }
};

使用長度爲1的滑動窗口在滑動,可是沒想到題目仍是會出現後面區間包含前面的狀況,這樣就要從新設計了
看到答案說sort函數排序能夠默認按照第一個第二個這樣排序,能夠排序以後在作,排序以後後面的值確定是大於等於前面的,可是還要考慮後面包含前面的狀況

考點:排序+數組
思路:先對二維數組表示的全部區間的左端點進行升序排序,而後從第二個區間(下標爲1)開始遍歷判斷是否能夠作合併操做:只要前一個區間的右端點大於等於當前區間的左端點,那說明這兩個區間能夠合併,合併後的區間左端點是前一個區間的左端點,只須要更新右端點爲兩個區間右端點的最大值便可。
不然,說明兩個區間沒有重疊,直接更新表示不重複區間的pos值

做者:xing2fan
連接:https://leetcode-cn.com/problems/merge-intervals/solution/qu-jian-he-bing-de-pai-xu-fa-by-xing2fan/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        if (!intervals.size()) return {};

        //先把區間集合按照左端點從小到大進行排序
        sort(intervals.begin(), intervals.end(), less<vector<int>>());
        int pos = 0;//pos的值是每一個不重疊的區間
        //直接在原區間上作就能夠
        //從第二個區間開始去比較
        for (int i = 1; i < intervals.size(); ++i) 
        {
            //兩個區間若能合併,則第一個區間的右端點必定大於等於第二個區間的左端點
            //好比[1,3] [2,6]
            if (intervals[pos][1] >= intervals[i][0]) 
            {
                //第一個區間的尾部須要更新爲:兩個區間的最大值即[1,6]
                intervals[pos][1] = max(intervals[pos][1], intervals[i][1]);
            } 
            else//沒有重疊時 
            {
                //[1,6] [2,8]====>區間1就是目前的這個區間
                intervals[++pos] = intervals[i];
            }
        }

        intervals.resize(pos + 1);//把最後的不用的彈出
        return intervals;
    }
   
};

做者:xing2fan
連接:https://leetcode-cn.com/problems/merge-intervals/solution/qu-jian-he-bing-de-pai-xu-fa-by-xing2fan/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        if (intervals.empty()) {
            return intervals;
        }
        sort(intervals.begin(), intervals.end());
        vector<vector<int>> result{ intervals.front() };
        for (auto&& interval : intervals) {
            if (interval.front() > result.back().back()) {
                result.emplace_back(move(interval));
            } else {
                result.back().back() = max(interval.back(), result.back().back());
            }
        }
        return result;
    }
};

做者:klaxxi
連接:https://leetcode-cn.com/problems/merge-intervals/solution/c-pai-xu-tan-xin-by-klaxxi/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

57. 插入區間

和上題同樣,先插入再作

class Solution {
public:
    vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) {
        vector<vector<int>> res;
        if(newInterval.empty())return intervals;
        intervals.push_back(newInterval);
        sort(intervals.begin(),intervals.end());
        res.push_back(intervals[0]);
        for(int i =1; i< (int)intervals.size() ;i++)
        {
            if(intervals[i][0]<= res.back()[1])
            {
                res.back()[1] = max(res.back()[1], intervals[i][1]);
            }
            else
            {
                res.push_back(intervals[i]);
            }
        }
        return res;
        
    }
};

62. 不一樣路徑(dp)

在多種題解法中,動態規劃每每是最簡單的一種,而遞歸每每是麻煩也很差寫的一種,因此最好仍是先考慮dp,這道理可想而知dp較爲簡單,以前作的dp都是在一維上,這回是二維上的dp

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> board(m,vector<int>(n,0));
        for(int i = 0 ; i <m ;i++)
        {
            board[i][0]=1;
        }
        for(int j = 0; j<n ;j++)
        {
            board[0][j]=1;
        }
        for(int i = 1; i<m ;i++)
        {
            for(int j = 1 ; j<n ;j++)
            {
                board[i][j] = board[i-1][j] + board[i][j-1];
            }
        }      
        return board[m-1][n-1];  
    }
};

64. 最小路徑和(dp)

很典型的動態規劃題目,和上題同樣

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        if(grid.empty())return 0;
        int m = grid.size();
        int n = grid[0].size();
        vector<vector<int>> board(m,vector<int>(n,0));
        board[0][0]=grid[0][0];
        for(int i = 1 ; i< n ;i++)
        {
            board[0][i] = grid[0][i]+board[0][i-1];
        }
        for(int i = 1 ; i< m ; i++)
        {
            board[i][0] = grid[i][0]+board[i-1][0];
        }
        for(int i = 1 ; i < m ;i++)
        {
            for(int j = 1 ; j< n; j++)
            {
                board[i][j] = grid[i][j] + min(  board[i-1][j],board[i][j-1]);
            }
        }
        return board[m-1][n-1];
    }
};

69. x 的平方根(二分法)

雖然就是典型的二分法,可是有不少值得講究的地方:
1.mid最好設置爲兩個的和除以2再加1,擴大範圍更好,否則可能會chucuo
2.初始值能夠設置的更小點
3.最後是left和right的變化問題,最後兩個都變化或者至少一個變化,而後返回left就能夠,沒必要要返回mid

class Solution {
public:
    int mySqrt(int x) {
        if(x==0)return 0;
        long left = 1;
        long right = x;
        while(left<right)
        {
            long mid = (left+right)/2+1;
            if(mid==x/mid)return mid;
            else if(mid>x/mid)
            {right = mid-1;}
            else
            {left = mid;}
        }
        return left;
    }
};

70. 爬樓梯(dp)

動態規劃

class Solution {
public:
    int climbStairs(int n) {
        if(n==0)return 0;
        if(n==1)return 1;
        if(n==2) return 2;
        vector<int> dp(n+1,0);
        dp[0]=0;
        dp[1]=1;
        dp[2]=2;
        for(int i = 3 ; i<n+1; i++)
        {
            dp[i] = dp[i-1]+ dp[i-2];
        }
        return dp[n];
    }
};

72. 編輯距離

class Solution {
public:
    int minDistance(string word1, string word2) {
        int len1 = word1.size();
        int len2 = word2.size();
        vector<vector<int>> dp(len1+1, vector<int>(len2+1,0));
        for(int i = 0 ;i<=len1; i++)
        {
            dp[i][0] = i;
        }
        for(int j = 0 ; j<=len2 ;j++)
        {
            dp[0][j] = j;
        }
        
        for(int i=1 ;i<=len1 ;i++)
        {
            for(int j=1; j<=len2 ;j++)
            {
                if(word1[i-1]==word2[j-1])
                {
                    dp[i][j] = dp[i-1][j-1] ;
                }
                else
                {
                    dp[i][j] = min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1;
                }
            }

        }
        return dp[len1][len2];
    }
};

73. 矩陣置零

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        if(matrix.size()==0)return;
        vector<int> row;
        vector<int> col;
        int len1 = matrix.size();
        int len2 = matrix[0].size();
        for(int i= 0 ;i<len1 ; i++)
        {
            for(int j = 0 ; j <len2 ;j++)
            {
                if(matrix[i][j]==0) 
                {
                    row.push_back(i);
                    col.push_back(j);
                }
            }
        }
        for(auto i :row)
        {
            for(int j = 0 ; j<len2 ;j++)
            {
                matrix[i][j]=0;
            }
        }
        for(auto j:col)
        {
            for(int i = 0 ; i<len1 ; i++)
            {
                matrix[i][j] = 0;
            }
        }
        return;
    }
};

75. 顏色分類(三數快排)

只有三個數的時候排序能夠如此簡單

class Solution {
public:
    void sortColors(vector<int>& nums) {
        int left = 0 , right = nums.size()-1;
        for(int i = left ;i<=right ;i++)
        {
            if(nums[i]==0)swap(nums[left++],nums[i]);
            if(nums[i]==2)swap(nums[right--],nums[i--]);

        }
        return;
    }
};

快速排序

鞏固一下快速排序,要特注意的是先循環j再循環i

class Solution {
public:
    void quicksort(int left,int right, vector<int>& nums)
    {
        if(left>=right)return;
        int i = left;
        int j = right;
        while(i<j)
        {
            while(i<j && nums[j]>=nums[left])j--;
            while(i<j && nums[i]<=nums[left])i++;
            
            if(i<j)
            {
                swap(nums[i],nums[j]);
            }

        }
        swap(nums[left],nums[i]);
        quicksort(left,i-1,nums);
        quicksort(i+1,right,nums);
    }
    void sortColors(vector<int>& nums) {
        int len = nums.size();
        if(len==0 || len==1)return;
        quicksort(0,len-1,nums);
        return;
    }
};

74. 搜索二維矩陣

採用了兩個二分法模板作的,注意銜接的時候,要考慮小於第一個個值的狀況

class Solution {
public:
    bool searchMatrix(vector<vector<int>>& matrix, int target) {
        if(matrix.empty())return false;
        if(matrix[0].empty())return false;
        int len = matrix.size();
        int left = 0,right = len;
        while(left<right)
        {
            int mid = (left+right)/2;
            if(matrix[mid][0]==target)return true;
            else if(matrix[mid][0]<target)
            {
                left = mid+1;
            }
            else
            {
                right = mid;
            }
        }
        int temp = left-1;
        if(temp<0)return false;
        len = matrix[0].size();
        left = 0;right=len;
        while(left<right)
        {
            int mid = (left+right)/2;
            if(matrix[temp][mid]==target) return true;
            else if(matrix[temp][mid]<target)
            {
                left=mid+1;
            }
            else
            {
                right=mid;
            }
        }
        return false;
    }
};

77. 組合

因爲這個pos表明的是初始位置,當進行過一次遍歷後,這個值也要加1才行

class Solution {
private:
vector<vector<int> > res;
vector<int> path;
public:
    void dfs(int n,int pos, int k)
    {
        if (path.size()==k)
        {
            res.push_back(path);
        }
        for(int i = pos; i<= n; i++)
        {
            path.push_back(i);
            dfs(n,pos+1,k);
            path.pop_back();
            pos++;
        }
    }

    vector<vector<int>> combine(int n, int k) {
        if(n==0||k==0) return res;
        dfs(n,1,k);
        return res;
    }
};

其餘解答,道理是同樣的

class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        vector<vector<int>> list;
        vector<int> result;
        dfs(list,result,n,k,0,-1);       
        return list;
    }
    void dfs(vector<vector<int>>& list, vector<int>& result, int n, int k, int pos,int pre){
        if(pos == k){
            list.push_back(result);
            return;
        }
        if((pos + (n-pre)) <= k)return;//剪枝,添加以後用時節省了2/3
        //在當前對不合理的取值進行判斷,結束下一層的遞歸操做。
        //若是當前剩餘可操做數字的個數即(n-pre)< k-pos+1(即組合中有待賦值的位置個數),(+1是由於當前pos尚未進行操做),則能夠判斷該條路徑不可能獲得正確的解,再也不向下探尋。
        for(int i=pre+1; i<n ; i++){
            result.push_back(i+1);
            pre = i;
            dfs(list,result,n,k,pos+1,pre);
            result.pop_back();//回溯
        }
        return;
    }
};

做者:rouzi
連接:https://leetcode-cn.com/problems/combinations/solution/dfsjian-zhi-by-rouzi/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

78. 子集

適合用遞歸作,可是遞歸併很差寫
下面這個遞歸式return,是在最後(至關於沒有),這個結構比較少見,主要是由於沒有肯定的返回條件,進行一個遍歷,而後在遍歷的過程當中不斷的放入大的容器

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int> > res;
        vector<int> tmp;
        helper(res,tmp,nums,0);
        return res;
    }
    void helper(vector<vector<int> >& res,vector<int> tmp,vector<int>& nums,int level){
        if(tmp.size()<=nums.size()){
            res.push_back(tmp);
        }
        for(int i=level;i<nums.size();i++){
            tmp.push_back(nums[i]);
            helper(res,tmp,nums,i+1);
            tmp.pop_back();
        }
        return;
    }
};

做者:Tangzixia
連接:https://leetcode-cn.com/problems/subsets/solution/liang-chong-fang-fa-qiu-jie-zi-ji-by-tangzixia/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
class Solution {
public:
    vector<vector<int>> ans;
    vector<int> tmp;
    void find(int dep, vector<int>& nums)
    {
        // 已經處理完最後一位,將目前存儲的集合存入 ans ,並回溯
        if(dep <= 0)
        {
            ans.push_back(tmp);
            return;
        }
        // 狀況一:集合中有該元素
        tmp.push_back(nums[dep - 1]);
        find(dep - 1, nums);
        tmp.pop_back();
        // 狀況二:集合中無該元素
        find(dep - 1, nums);
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        find(nums.size(), nums);
        return ans;
    }
};

做者:iswJXkYVv3
連接:https://leetcode-cn.com/problems/subsets/solution/c-0ms-132mb-shen-sou-yong-shi-ji-bai-100mark-by-is/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

79. 單詞搜索

因爲代碼太複雜沒有全寫完,可是道理應該是對的,遍歷每一個word中的字符,當找到該字符時就將下一個字符、找到的座標、board輸入到判斷函數中,當全部字符都判斷成功時纔算含有此字符串,道理時對的,但不算是dfs或者回溯方法

class Solution {
private:
    string s1;
    int h=0;
    int l = 0;
public:

    //位置必須傳遞,才能和上次有關聯
    bool dfs(char s1, string& s, int a , int b , vector<vector<char>>& board)
    {
        if(a==0)
        {
            if(b==0)
            {
                if(board[a+1][b]==s1 || board[a][b+1]==s2){return true;}}
            }
            if(b==l-1 )
            {
                if(board[a+1][b]==s1 || board[a][b-1]==s2){return true;}}
            }
            else
            {
                if(board[a+1][b]==s1 || board[a][b+1]==s2 || board[a][b-1]==s2){return true;}}
            }
            
            for(int j = 0 ; j <b ; j++ )
            {
                if(board[a+1][j]==s1){return true;}

        }
        if(a==h-1)
        {
            for(int j = 0 ; j <b ; j++ )
            {
                if(board[a-1][j]==s1){return true;}
            }
        }
        if(b==l-1)
        {
            for(int i = 0 ; i<a; i++)
            {
                if(board[i][])
            }
        }        
        
        
        for(auto i :s)
        {
            
            dfs(i,s,)
            
        }

    }
    bool exist(vector<vector<char>>& board, string word) {
        h = board.size();
        l = board[0].size();
        //如何獲取第一次的正確位置,或者進行遍歷尋找
        for(int i = 0 ; i< h;i++ )
        {
            for(int j = 0; j<l ; j++)
            {
                if (board[i][j]==word[0])//這裏不用判斷
                {
                    if(dfs(word[1],word,i,j,board)){return true;}
                }
            }
        }
        return false;
        
    }
};
class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) {
        if(board.size() == 0) return false;
        for (int i=0;i<board.size();i++){
            for(int j=0;j<board[0].size();j++){
                if (dfs(board,word,i,j,0)){
                    return true;
                }
            }
        }
        return false;
    }

    bool dfs(vector<vector<char>>& board, string& word, int i,int j,int length){
        if(i>=board.size()||j>=board[0].size()||i<0||j<0||length>=word.size()||word[length]!=board[i][j]){
            return false; //出界或者最後一位不相等
        }
        if(length==word.size()-1&&word[length]==board[i][j]){//word不爲空且最後一位和當前位置相等
            return true;
        }
        char temp=board[i][j];
        board[i][j]='0';//這個位置
        bool flag=dfs(board,word,i,j+1,length+1)||dfs(board,word,i,j-1,length+1)||dfs(board,word,i+1,j,length+1)||dfs(board,word,i-1,j,length+1); //找四邊的每個點,若是點
        board[i][j]=temp;  // 標記過的點恢復原狀,以便進行下一次搜索
        return flag;
    }
};

做者:z1m
連接:https://leetcode-cn.com/problems/word-search/solution/tu-jie-di-gui-shen-du-you-xian-sou-suo-by-z1m/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

僞代碼

dfs(i,j,word, board,len)
{
	if(i,j已經出界 || 這個位置和wordlen元素不相等)
	{返回false}
	if(這個位置和word最後一維相等)
	{返回true}
	
}
exist()
{
	遍歷board,並對每個位置執行一次判斷//當每一個位置都輸入進去,直接進入dfs,判斷和第一位是否相等,若是不相等則到下一個位置,若是相等則進入函數主體,判斷四周的四個位置都和下一位相等,true的終止條件是到了最後一位並且與此位置相等。裏面有一點要注意爲了防止出現AEA這種又回去的狀況,在這次搜索中已經相等過的要設置爲‘0’防止回去
}

1.總結:dfs也能夠設置爲有類型的,當設置爲bool型這種特殊的類型時,要寫兩個終止條件,一個是true的,一個是false,false能夠是每次的回退條件,可是true必定是最終的判斷條件,剩下的函數主題就是默認的經過這次驗證

80. 刪除排序數組中的重複項 II

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int len = nums.size();
        int i = 0, j = 0;
        while(i<len)
        {
            int temp = i;
            while(i<len && nums[i]==nums[temp])i++;
            if(i-temp==1){nums[j++]=nums[temp];}
            else if(i-temp>=2){nums[j++]=nums[temp];nums[j++]=nums[temp];}
            
        }
        return j;
    }
};

81. 搜索旋轉排序數組 II

先去重

class Solution {
public:
    bool search(vector<int>& nums, int target) {
        if(nums.empty())return false;
        int j = 0;
        for(int i =1 ;i<(int)nums.size() ;i++)
        {if(nums[i]!=nums[j])nums[++j]=nums[i];}
        vector<int> num;
        num.assign(nums.begin(),nums.begin()+j+1);
        if((int)num.size()>1 && num[j]==num[0]){num.pop_back();}
        int right = num.size();
        int left = 0;
        while(left<right)
        {
            int mid = left + (right-left)/2;
            if(num[mid]==target){return true;}
            else if (num[mid]>target)
            {
                if(target>=num[0] || num[mid]<num[0]){right = mid;}
                else{left=mid+1;}
            }
            else
            {
                if(num[mid]>=num[0] ||target<num[0]){left=mid+1;}
                else{right=mid;}
            }
        }
        return false;        
    }
};

88. 合併兩個有序數組

class Solution {
public:
    void merge(vector<int>& arr1, int m, vector<int>& arr2, int n) {
	//int len1 = arr1.size();
	//int len2 = arr2.size();
    if(m==0)
    {
        arr1.assign(arr2.begin(),arr2.end());
        return;
    }
    if(n==0) return;
	int i = m - 1;
	int j = n - 1;
	int k = m + n - 1;
	while (i>= 0 && j>= 0)
	{
		while (i>= 0 && j>=0 && arr1[i] >= arr2[j])
		{
			arr1[k--] = arr1[i--];
		}
		while (i >= 0 && j >= 0 && arr1[i] <= arr2[j])
		{
			arr1[k--] = arr2[j--];
		}

	}
    while (i>=0 )
    {
        arr1[k--] = arr1[i--];
    }
    while (j>=0)
    {
        arr1[k--] = arr2[j--];
    }
	return ;        
    }
};

91.

字符串轉數字

atoi(str.c_str());

字符轉數字

int(char-'0')

94. 二叉樹的中序遍歷

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
vector<int> res;
public:
    void dfs(TreeNode* root)
    {
        if(!root) return;

        dfs(root->left);
        res.push_back(root->val);
        dfs(root->right);
    }

    vector<int> inorderTraversal(TreeNode* root) {
        if(!root) return res;
        dfs(root);
        return res;
    }
};

95. 不一樣的二叉搜索樹 II

看不懂爲何這麼作
解法一徹底沒有用到查找二叉樹的性質,暴力嘗試了全部可能從而形成了重複。咱們能夠利用一下查找二叉樹的性質。左子樹的全部值小於根節點,右子樹的全部值大於根節點。

因此若是求 1…n 的全部可能。

咱們只須要把 1 做爲根節點,[ ] 空做爲左子樹,[ 2 … n ] 的全部可能做爲右子樹。

2 做爲根節點,[ 1 ] 做爲左子樹,[ 3…n ] 的全部可能做爲右子樹。

3 做爲根節點,[ 1 2 ] 的全部可能做爲左子樹,[ 4 … n ] 的全部可能做爲右子樹,而後左子樹和右子樹兩兩組合。

4 做爲根節點,[ 1 2 3 ] 的全部可能做爲左子樹,[ 5 … n ] 的全部可能做爲右子樹,而後左子樹和右子樹兩兩組合。

n 做爲根節點,[ 1… n ] 的全部可能做爲左子樹,[ ] 做爲右子樹。

至於,[ 2 … n ] 的全部可能以及 [ 4 … n ] 以及其餘狀況的全部可能,能夠利用上邊的方法,把每一個數字做爲根節點,而後把全部可能的左子樹和右子樹組合起來便可。

若是隻有一個數字,那麼全部可能就是一種狀況,把該數字做爲一棵樹。而若是是 [ ],那就返回 null。

做者:windliang
連接:https://leetcode-cn.com/problems/unique-binary-search-trees-ii/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-2-7/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

class Solution {
public:
    vector<TreeNode*> helper(int start,int end){
        vector<TreeNode*> ret;
        if(start > end)
            ret.push_back(nullptr);
        
        for(int i=start;i<=end;i++){
            vector<TreeNode*> left = helper(start,i-1);
            vector<TreeNode*> right = helper(i+1,end);
            for(auto l : left){
                for(auto r : right){
                    TreeNode* root = new TreeNode(i);
                    root -> left = l;
                    root -> right = r;
                    ret.push_back(root);
                }
            }
        }
        return ret;
    }
    
    vector<TreeNode*> generateTrees(int n) {
        vector<TreeNode*> ret;
        if(n == 0)
            return ret;    
        ret = helper(1,n);
        return ret;
    }
};

做者:black-hole
連接:https://leetcode-cn.com/problems/unique-binary-search-trees-ii/solution/c-30xing-dai-ma-di-gui-by-black-hole/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

97. 交錯字符串

能正確判斷,可是超時了,由於遞歸的效率比較低;
對於字符串的題,使用遞歸都比較耗時

class Solution {
private:
int len1;
int len2;
int len3;
public:
    bool dfs(int i, int j, int k, string& s1, string &s2, string &s3)
    {
        if(i==len1 && j==len2 && k==len3) return true;   
        
        if(i<len1 && j<len2)
        {
            if(s2[j]!=s3[k]&&s1[i]==s3[k])
            {
                return dfs(i+1,j,k+1,s1,s2,s3);
            } 
            if(s1[i]!=s3[k]&&s2[j]==s3[k])
            {
                return dfs(i,j+1,k+1,s1,s2,s3);
            }
            if(s1[i]==s3[k]&&s2[j]==s3[k])
            {
                return dfs(i+1,j,k+1,s1,s2,s3)||dfs(i,j+1,k+1,s1,s2,s3);
            }
            if(s1[i]!=s3[k]&&s2[j]!=s3[k])
            {
                return false;
            }
        }
        if(i==len1 && j<len2)
        {
            if(s2[j]==s3[k]) return dfs(i,j+1,k+1,s1,s2,s3);
            else{return false;}
        }
        if(i<len1 && j==len2)
        {
            if(s1[i]==s3[k]) return dfs(i+1,j,k+1,s1,s2,s3);
            else{return false;}
        }
        

    }

    bool isInterleave(string s1, string s2, string s3) {
        len1 = s1.size();
        len2 = s2.size();
        len3 = s3.size();
        if(len1+len2 != len3) return false;
        if(s1.empty()&&s2.empty()&&s3.empty()) return true;
        return dfs(0,0,0,s1,s2,s3);
    }
};

98. 驗證二叉搜索樹(dfs)

寫了一堆不正確的代碼,四層遞歸

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
public:
    
    //用來遍歷,得到全部節點下的值
    void dfs1(TreeNode* root, vector<int>& res)
    {
        if(!root) return;
        res.push_back(root->val);
        dfs1(root->left,res);
        dfs1(root->right,res);
    }


    //用來判斷每一個節點做爲根節點時候是否符合標準
    bool dfs2(TreeNode* root, vector<int> r1, vector<int> r2)
    {
        if(r1.empty() && r2.empty()) return true;
        if(!r1.empty() && r2.empty())
        {
            for(auto i:r1)
            {
                if(i>=root->val)return false;
            }
        }
        if(r1.empty() && !r2.empty())
        {
            for(auto i:r2)
            {
                if(i<=root->val)return false;
            }
        }
        for(auto i:r1)
        {
            if(i>=root->val)return false;
        }
        for(auto i:r2)
        {
            if(i<=root->val)return false;
        }
        return true;
    }

    //對每個進行判斷
    bool df3(TreeNode* root)
    {
        vector<int> left;
        dfs1(root->left,left);
        vector<int> right;
        dfs1(root->right,right);
        return dfs2(root,left,right);        
    }
    //遍歷並返回判斷結果
    void df4(TreeNode* root, bool& flag)
    {
        if(!root) return;
        
        if(!df3(root)) flag = false;
        isValidBST(root->left);
        isValidBST(root->right);        
    }
    bool isValidBST(TreeNode* root) {
        if(!root) return true;
        
        bool flag=true;
        df4(root,flag);
        if(flag==true)return true;
        return false;

    }
};

以前的思路是判斷兩百邊的數組,可是得到數組就須要進行遍歷,十分麻煩,下面的解法目的不是求節點是否在左右節點數組的中間,而是每一個節點和一個區間進行比較,這個區間一開始是無限大,每通過一個節點就將區間範圍縮小,往左節點走時父節點做爲有邊界,往右邊界走時父節點做爲左邊界,這樣能夠不斷的將父節點的區間範圍傳遞下去,十分巧妙
思路:引入上下邊界

對於樹的每一個節點 val ,設其上下邊界 low , high。(用 long 防止 INT_MAX 溢出 )
判斷根結點時,須知足 low < val < high ,不然返回 false
判斷左節點時,僅 上界 變化 ( 新上界爲 high 與 val 較小值。又因 val 必小於 high,故新上界爲 val )
判斷右節點時,僅 下界 變化 ( 同理,新下界爲 val )

做者:penn-10
連接:https://leetcode-cn.com/problems/validate-binary-search-tree/solution/cyu-yan-yan-zheng-er-cha-sou-suo-shu-by-penn-10/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

bool fun(struct TreeNode* root, long low, long high) {
    if (root == NULL) return true;
    long num = root->val;
    if (num <= low || num >= high) return false;
    return fun(root->left, low, num) && fun(root->right, num, high);
}
bool isValidBST(struct TreeNode* root){
    return fun(root, LONG_MIN, LONG_MAX);
}

做者:penn-10
連接:https://leetcode-cn.com/problems/validate-binary-search-tree/solution/cyu-yan-yan-zheng-er-cha-sou-suo-shu-by-penn-10/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

100. 相同的樹

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        //一種適用性很強的辦法,都通過層序遍歷,比較最後的結果,但這確定不是最優解法
        if(p==NULL && q==NULL)return true;
        if(p==NULL && q!= NULL)return false;
        if(p!=NULL && q==NULL)return false;
        if(p->val != q->val)return false;
        return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
    }
};

101. 對稱二叉樹

易錯點時三個條件不能少,並且注意對稱時左節點的左孩子和右節點的右孩子相比

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
public:
    bool dfs(TreeNode* root1, TreeNode* root2)
    {   
        if(root1==NULL && root2==NULL){return true;}
        if(root1==NULL && root2!=NULL){return false;}
        if(root1!=NULL && root2==NULL){return false;}
        if(root1->val!=root2->val){return false;}
        
        return dfs(root1->left,root2->right) && dfs(root1->right,root2->left);
    }
    
    bool isSymmetric(TreeNode* root) {
        if(root==NULL){return true;}
        return dfs(root->left,root->right);

    }
};

102. 二叉樹的層序遍歷

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
private:
vector<vector<int> > res;
public:
    void dfs(vector<TreeNode*> cur)
    {
        if(cur.size()==0){return;}
        vector<int> temp;
        vector<TreeNode*> next;
        for(auto i:cur)
        {
            temp.push_back(i->val);
            if(i->left!=NULL){next.push_back(i->left);}
            if(i->right!=NULL){next.push_back(i->right);}
        }
        res.push_back(temp);
        dfs(next);

    }
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(root==NULL){return res;}
        vector<TreeNode*> cur;
        cur.push_back(root);
        dfs(cur);
        return res;
    }
};

使用隊列的方法

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> res;
        vector<int> level;
        if(root == nullptr) return res;
        queue<TreeNode*> que;
        que.push(root);
        que.push(nullptr);
        TreeNode *cur = nullptr;
        while(que.size()){
            cur = que.front();
            que.pop();
            if(cur){
                level.push_back(cur->val);
                if(cur->left) que.push(cur->left);
                if(cur->right) que.push(cur->right);
            }else{
                res.push_back(level);
                level.resize(0);
                if(que.size() > 0) que.push(nullptr);
            }
        }
        return res;
    }
};

103. 二叉樹的鋸齒形層次遍歷

印象中是使用堆棧的,可是直接用一個bool量來標記也很方便
還能夠正常層序遍歷,而後隔一個倒敘一下就能夠,和1007同樣,都是遍歷以後對數組作處理

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
private:
vector<vector<int> > res;
bool flag;
public:
    void dfs(vector<TreeNode*> cur)
    {
        if(cur.size()==0){return;}
        vector<TreeNode*> next;
        vector<int> temp;
        for(auto i:cur)
        {
            if(i->left!=NULL){next.push_back(i->left);}
            if(i->right!=NULL){next.push_back(i->right);}
            temp.push_back(i->val);
        }
        if(!flag){reverse(temp.begin(),temp.end());}
        flag = !flag;
        res.push_back(temp);
        dfs(next);
    }
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        if(root==NULL){return res;}
        vector<TreeNode*> temp;
        temp.push_back(root);
        flag = 1;
        dfs(temp);
        return res;
    }
};

104. 二叉樹的最大深度(***********)

有一種很簡單的寫法,不少處會用到

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(root==NULL)return 0;
        return max(  maxDepth( root->left) , maxDepth( root->right)  )+1;
    }
};

通常最終值放到private處定義,中間每次須要用到的參量放入遞歸的參數列表

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
private:

int max;
public:
    void dfs(TreeNode* root, int num)
    {
        if(root->left==NULL&&root->right==NULL){return;}
        
        if(root->left!=NULL)
        {
            num++;
            if(max<num){max=num;}
            dfs(root->left,num);
            num--;
        }
        if(root->right!=NULL)
        {
            num++;
            if(max<num){max=num;}
            dfs(root->right,num);
            num--;
        }

    }
    int maxDepth(TreeNode* root) {
        max=0;
        if(root==NULL){return max;}       
        max=1;
        dfs(root,1);
        return max;
    }
};

105. 從前序與中序遍歷序列構造二叉樹

主要問題是代碼寫的太複雜了,可是思路是正確的,這裏的遞歸函數須要設置成返回節點型,注意這種的最後仍是要吧頭節點返回來,否則第一個遞歸函數就沒有返回值了

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
private:
    
public:
    TreeNode* dfs(vector<int>& preorder, vector<int>& inorder)
    {
        if(preorder.size()==0){return NULL;}
        if(preorder.size()==1)
        {
            TreeNode* temp = new TreeNode(preorder[0]);
            return temp;
        }
        int mid = find(inorder.begin(),inorder.end(),preorder[0])-inorder.begin();
        TreeNode* root= new TreeNode(preorder[0]);

        vector<int> p1(preorder.begin()+1,preorder.begin()+ mid+1);
        vector<int> q1(inorder.begin() ,inorder.begin()+ mid);
        root->left = dfs(p1,q1);
        
        vector<int> p2(preorder.begin()+mid+1, preorder.end());
        vector<int> q2(inorder.begin()+mid+1 ,inorder.end());        
        root->right =dfs(p2,q2);

        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        
        if(preorder.size()==0){return NULL;}
        TreeNode* root = dfs(preorder,inorder);
        return root;
    }
};

在遞歸的過程當中傳遞了不少參數,代碼量減小

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int pos = 0;
        return buildTree(preorder, pos, inorder, 0, inorder.size()-1);
    }

    TreeNode* buildTree(vector<int>& preorder, int& pos, vector<int>& inorder, int left, int right) {
        if (pos >= preorder.size()) return 0;
        int i = left;
        for (i = left; i <= right; ++i) {
            if (inorder[i] == preorder[pos]) break;
        }
        TreeNode* node = new TreeNode(preorder[pos]);
        if (left <= i-1) node->left = buildTree(preorder, ++pos, inorder, left, i-1);  // 左子樹
        if (i+1 <= right) node->right = buildTree(preorder, ++pos, inorder, i + 1, right);  // 右子樹
        return node;
    }
};

做者:yuexiwen
連接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/c-fen-zhi-by-yuexiwen/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

106. 從中序與後序遍歷序列構造二叉樹

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
public:
    TreeNode* dfs(vector<int>& inorder,vector<int>& postorder)
    {
        if(inorder.size()==0){return NULL;}
        if(inorder.size()==1)
        {
            TreeNode* temp = new TreeNode(inorder[0]);
            return temp;
        }

        int mid = find(inorder.begin(), inorder.end(), postorder[postorder.size()-1] )- inorder.begin();
        TreeNode* root = new TreeNode(inorder[mid]);
        vector<int> l1(inorder.begin(), inorder.begin()+mid);
        vector<int> l2(postorder.begin(), postorder.begin()+mid);
        root->left = dfs(l1, l2);
        vector<int> r1(inorder.begin()+mid+1, inorder.end());
        vector<int> r2(postorder.begin()+mid, postorder.end()-1);
        root->right = dfs(r1,r2);
        return root;
    }

    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(postorder.size()==0){return NULL;}
        TreeNode* root =  dfs(inorder,postorder);
        return root;
    }
};

107. 二叉樹的層次遍歷 II

徹底能夠從上到下遍歷,而後拿一個堆棧存放,或者直接返回reverse的結果?!不是更簡單,看來在使用堆棧的倒敘功能時,用reverse可能更方便

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
private:
stack<vector<int>> res;
public:
    void dfs(vector<TreeNode*> cur)
    {
        if(cur.size()==0){return;}

        vector<int> temp;
        vector<TreeNode*> next;
        for(auto i:cur)
        {
            if(i->left!=NULL){next.push_back(i->left);}
            if(i->right!=NULL){next.push_back(i->right);}
            temp.push_back(i->val);
        }
        res.push(temp);
        dfs(next);
    }
    
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        
        vector<TreeNode*> temp;
        temp.push_back(root);
        vector<vector<int>> r;
        if(root==NULL){return r;}
        dfs(temp);
        while(!res.empty())
        {
            r.push_back(res.top());
            res.pop();
        }
        return r;
    }
};

108. 將有序數組轉換爲二叉搜索樹(****)

dfs方法

class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return bst(nums,0,nums.size()-1);
    }
    TreeNode* bst(vector<int>& a,int l,int r){
        if(l>r) return NULL;
        int mid=(r-l)/2+l;
        TreeNode* root=new TreeNode(a[mid]);
        root->left=bst(a,l,mid-1);
        root->right=bst(a,mid+1,r);
        return root;
    }
};


做者:dai-52
連接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/solution/cdi-gui-jie-fa-by-dai-52-2/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

109. 有序鏈表轉換二叉搜索樹

轉成數組是一種方法,另一種是使用快慢指針,把中間的找出來,這部分放到dfs最開始的地方

/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
public:
    TreeNode* dfs(vector<int>& nums, int left, int right)
    {
        if(left>right) return NULL;
        int mid = left+(right-left)/2;
        auto root = new TreeNode(nums[mid]);
        root->left = dfs(nums,left,mid-1);
        root->right = dfs(nums,mid+1,right);
        return root;

    }
    TreeNode* sortedListToBST(ListNode* head) {
        //其實跟上一題區別不大,只是數組換成了鏈表,能夠把鏈表轉換成數組,而後和上題同樣
        vector<int> v;
        while(head){v.push_back(head->val);head=head->next;}
        int len = v.size();
        return dfs(v,0,len-1);
    }
};

110. 平衡二叉樹

有考慮的方法是寫一個這個節點下面深度的函數,而後遞歸每個節點的左右節點進行判斷,可是以前求最大深度的代碼就寫的很複雜
下面這個求深度的代碼十分簡單,不用進行num的維護每次返回值加1就能夠了,代筆層數,這道題雙遞歸函數十分巧妙
三個條件放再一塊兒判斷會更簡便,不過傳入單個節點會稍微比較難理解,爲何到了葉節點就返回true了

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
public:
    bool isBalanced(TreeNode* root) {
        if(!root) return true;
        
        int d = abs(depth(root->left)-depth(root->right)); //當前節點的左右子樹的高度差
        
        return (d<=1) && (isBalanced(root->left)) && (isBalanced(root->right));
    }
    
    // 求解二叉樹深度(104題)
    int depth(TreeNode* node)
    {
        if(node ==NULL) return 0;
        return max( depth(node->left), depth(node->right) )+1;
    }
    
};

做者:fly_sky
連接:https://leetcode-cn.com/problems/balanced-binary-tree/solution/c-ban-ben-dai-ma-jian-ji-by-fly_sky/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

111. 二叉樹的最小深度

形式基本上是仿照最大深度來的,可是有一點不同,要注意對最小深度的定義,不是出現null就行,而是必須出現葉節點,即自己存在可是左右孩子不存在的,這是惟一的狀況,因爲root可能會存在左右孩子爲null的狀況,因此不能將左右孩子直接輸入,而是將根節點輸入。

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
public:
    int minnn(TreeNode* root)
    {
        if(!root->left && !root->right){return 0;}
        if(root->left && !root->right){return minnn(root->left)+1;}
        if(!root->left && root->right){return minnn(root->right)+1;}
        return min(minnn(root->left),minnn(root->right))+1;
    }
    int minDepth(TreeNode* root) {
        if(!root){return 0;}
        return minnn(root)+1;
    }
};

112. 路徑總和

要注意幾點:
1.當根節點爲空,其路徑和不存在而不是爲空,0和空在這裏是不同的,以前這個地方就錯過
2.這題的終止條件是到葉節點,因此終結條件(正+負)必須是關於葉節點的
3.不管是最大最小仍是其餘,邏輯關係都體如今dfs的返回方式的邏輯關係上
4.sum這種變化的值能夠做爲參數

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
public:
    bool dfs(TreeNode* root, int sum)
    {
        if(!root->left && !root->right)
        { 
            if(root->val==sum)return true;
            return false;
        }
        if(!root->left && root->right)return dfs(root->right,sum-root->val);
        if(!root->right && root->left)return dfs(root->left,sum-root->val);
        return dfs(root->left,sum-root->val) || dfs(root->right,sum-root->val);
        
    }
    bool hasPathSum(TreeNode* root, int sum) {
        if(!root)return false;
        return dfs(root,sum);
    }
};

113. 路徑總和 II

難點是如何應對何時存節點,何時放節點的問題,這個能夠根據例子倒推一下

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
private:
vector<vector<int>> res;
vector<int> path;
public:
    void dfs(TreeNode* root,int sum)
    {
        
        if(!root->left && !root->right)
        {
            path.push_back(root->val);
            if(root->val==sum) res.push_back(path);
            path.pop_back();
            return;
        }
        if(root->left)
        {
            path.push_back(root->val);
            dfs(root->left,sum-root->val);
            path.pop_back();
        }
        if(root->right)
        {
            path.push_back(root->val);
            dfs(root->right,sum-root->val);
            path.pop_back();
        }
        
    }
    vector<vector<int>> pathSum(TreeNode* root, int sum) {
        if(!root)return res;
        dfs(root,sum);
        return res;
    }
};

114. 二叉樹展開爲鏈表

先先序遍歷展開爲一列,而後變成鏈表,先序遍歷的代碼時固定的,就像求最大深度那樣要記住

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
private:
vector<int> list;
public:
    //先序遍歷
    void dfs(TreeNode* root)
    {
        if(!root ) return ;
        list.push_back(root->val);
        dfs(root->left);
        dfs(root->right);
    }
    
    void dfs2(TreeNode* root,int pos, vector<int> list)
    {
        if(pos==list.size()) return;
        TreeNode* temp = new TreeNode(list[pos]);
        root->left = NULL;
        root->right = temp;
        dfs2(temp,pos+1,list);
    }    
    void flatten(TreeNode* root) {
        //作一下層序遍歷,求出數組,而後都放到右孩子上
        if(!root)return;
        dfs(root);
        dfs2(root,1,list);
        return;


    }
};

115. 不一樣的子序列

關於字符串的題使用遞歸由超時了,可是思路應該時對的:把t中的每一個字符在s中的位置求出來並組成一個二維數組,裏面存放每一個t中字符的位置,而後對這個dfs遞歸計數,在值小於前一個個時須要進行剪枝,這個遞歸和求全部根節點到子節點時的模板很是像

class Solution {

public:
    void dfs(int& num,vector<int>& path, int pos, vector<vector<int>>& board)
    {
        if(path.size()==board.size())
        {
            num++;
            return;
        }

        for(int i:board[pos])
        {
            if( pos==0 || (pos>0 && i>path[path.size()-1])  )
            {
                path.push_back(i);
                dfs(num,path,pos+1,board);
                path.pop_back();
            }
        }
    }
    
    int numDistinct(string s, string t) {
        if(s.empty())return 0;
        int lens = s.size();
        int lent = t.size();
        vector<vector<int>> board;
        for(int i = 0 ; i<lent ; i++)
        {
            vector<int> temp;
            for(int j = 0; j<lens ; j++)
            {
                if(s[j]==t[i])
                {
                    temp.push_back(j);
                }

            }
            board.push_back(temp);
        }
        int num = 0;
        vector<int> path;
        int pos = 0;
        dfs(num,path,pos,board);
        return num;

    }
};

116. 填充每一個節點的下一個右側節點指針(bfs)

dfs是深度優先遍歷,有前序中序後序,參數爲根節點;bfs是廣度優先遍歷,沒有什麼序之說,在遍歷是後習慣用一個數組存放每一層的全部節點或者節點值,參數爲數組
一般bfs用非遞歸隊列比較多,可是用遞歸也能夠較好的解決一些問題,自由的對結果進行調整,可是隊列很差拿出來

/* // Definition for a Node. class Node { public: int val; Node* left; Node* right; Node* next; Node() : val(0), left(NULL), right(NULL), next(NULL) {} Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} Node(int _val, Node* _left, Node* _right, Node* _next) : val(_val), left(_left), right(_right), next(_next) {} }; */
class Solution {
vector<vector<Node*>> res;
public:
    void bfs(vector<Node*> cur)
    {
        if(cur.empty())return;
        vector<Node*> temp;
        for(auto i:cur)
        {
            if(i->left)temp.push_back(i->left);
            if(i->right)temp.push_back(i->right);
        }

        bfs(temp);
        res.push_back(temp);
    }

    Node* connect(Node* root) {
       if(!root) return NULL;
       vector<Node*> cur;
       cur.push_back(root);
       res.push_back(cur);
       bfs(cur);
       for(auto i : res)
       {
           if(i.size()==1){continue;}
           int m = i.size();
           for(int j = 0 ; j< m-1; j++)
           {
               i[j]->next=i[j+1];
           }
       }
        return root;
    }
};

117. 填充每一個節點的下一個右側節點指針 II(bfs)

和116的代碼一摸同樣

118. 楊輝三角

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> res;
        if(numRows==0) return res;
        vector<int> t = {1};
        res.push_back(t);
        if(numRows==1) return res;
        t.push_back(1);
        res.push_back(t);
        if(numRows==2) return res;
        numRows -=2;
        vector<int> cur = {1,1};
        while(numRows--)
        {
            vector<int> temp;
            temp.push_back(1);
            int len = cur.size();
            for(int i = 0 ; i<len-1 ; i++)
            {
                temp.push_back(cur[i]+cur[i+1]);
            }
            temp.push_back(1);
            cur.assign(temp.begin(),temp.end());
            res.push_back(cur);
        }
        return res;
    }
};

119. 楊輝三角 II

class Solution {
public:
    vector<int> getRow(int numRows) {
        vector<int> t = {1};
        if(numRows==0) return t;
        t.push_back(1);
        if(numRows==1) return t;
        numRows -=1;
        vector<int> cur = {1,1};
        while(numRows--)
        {
            vector<int> temp;
            temp.push_back(1);
            int len = cur.size();
            for(int i = 0 ; i<len-1 ; i++)
            {
                temp.push_back(cur[i]+cur[i+1]);
            }
            temp.push_back(1);
            cur.assign(temp.begin(),temp.end());
        }
        return cur;        
    }
};

額外的空間也能夠不使用,可是要修改原數據,不太好,因此就用了額外的 n*sizeof(int)的空間。
line用於記錄n層到n-1層最短的路徑長度,其初始值爲triangle的第n行。其遞歸公式爲:

line[j] = triangle[i][j] + min(line[j], line[j + 1]),i 表示當前自下向上到達第 i 層。
line[j]=triangle[i][j]+min(line[j],line[j+1]),i表示當前自下向上到達第i層。

做者:liushang-leecode
連接:https://leetcode-cn.com/problems/triangle/solution/dong-tai-gui-hua-zi-di-xiang-shang-ke-yi-shi-yong-/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        int n = triangle.size();
        vector<int> line(triangle[n - 1]);
        for (int i = n - 2; i >= 0; i--)
            for (int j = 0; j <= i; j++)
                line[j] = triangle[i][j] + min(line[j], line[j + 1]);
        return line[0];
    }
};

做者:liushang-leecode
連接:https://leetcode-cn.com/problems/triangle/solution/dong-tai-gui-hua-zi-di-xiang-shang-ke-yi-shi-yong-/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

121. 買賣股票的最佳時機(dp)

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.empty())return 0;
        int dp=prices[0],res = 0;
        for(int i = 1; i< (int)prices.size() ;i++)
        {
            dp = min(dp,prices[i]);
            res = max(res, prices[i]-dp);
        }
        return res;
    }
};

一次遍歷法,不是特別好理解

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int inf = 1e9; //很大的值
        int minprice = inf, maxprofit = 0;
        for (int price: prices) {
            maxprofit = max(maxprofit, price - minprice);
            minprice = min(price, minprice);
        }
        return maxprofit;
    }
};

做者:LeetCode-Solution
連接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/121-mai-mai-gu-piao-de-zui-jia-shi-ji-by-leetcode-/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        if(len==0 || len==1)return 0;        
        int minvalue = prices[0];
        int maxvalue = INT_MIN;
        for(int i = 1 ; i<len ; i++)
        {
            minvalue = min(minvalue,prices[i-1]);
            maxvalue = max(maxvalue,prices[i]-minvalue);
        }
        if(maxvalue<0)return 0;
        return maxvalue;
    }
};

動態規劃法

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if (n == 0) return 0; // 邊界條件
        int minprice = prices[0];
        vector<int> dp (n, 0); //新建一個數組
	//在動態變化中維護了最小值,老是能得到這個點以前的最小值
	//最後原本不用再和本身比較了,可是題目有一個特殊要求,就是不能小於0,因此再生成這個動態數組的時候,每次都要和0比較,若是小於0就不要了
        for (int i = 1; i < n; i++){
            minprice = min(minprice, prices[i]);
            dp[i] = max(dp[i - 1], prices[i] - minprice);
        }
        return dp[n - 1];
    }
};

做者:z1m
連接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/gu-piao-wen-ti-python3-c-by-z1m/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

122. 買賣股票的最佳時機 II

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int res = 0;
        for(int i=1; i< (int)prices.size() ;i++)
        {
            res += (prices[i]>prices[i-1])?(prices[i]-prices[i-1]):0;
        }
        return res;
    }
};

這道題不適合動態規劃,能夠用貪心結合雙指針作
不用非等到上升到最高點纔買,只要上升一次就買一次,低了就不動

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        //快慢指針標記
        int i=0,j=1,sum=0;
        //判斷vector大小
        if(prices.size()<=1)
        return 0;
        
        //兩個指針一直緊挨在一塊兒,只有j的值大於i的值時,就把差值加入sum中
        while(j<prices.size()){
            if(prices[j]-prices[i]>0)
                sum+=(prices[j]-prices[i]);

                i++;
                j++;
        }
        return sum;
    }
};

做者:zhong-zhong-ban-da-dui-chang
連接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/solution/ctan-xin-suan-fa-by-zhong-zhong-ban-da-dui-chang/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

123. 買賣股票的最佳時機 III

是在上一題的基礎上作的,可是次數再多就不行了,並且這種雙循環方式也超時了,可是思路是對的

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.empty())return 0;
        int res1 = 0, dp1 = prices[0], res = 0;
        for(int i =1 ; i< (int)prices.size() ;i++)
        {
            dp1 = min(dp1, prices[i]);
            res1 = max(res1, prices[i]-dp1);
            int dp2 = prices[i];
            int res2 = 0;
            for(int j = i+1 ; j<(int)prices.size() ;j++)
            {
                dp2 = min(dp2, prices[j]);
                res2 = max(res2, prices[j]-dp2);                
            }
            res = max(res, res1+res2);
        }
        return res;
    }
};

124. 二叉樹中的最大路徑和(dfs,不懂)

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
public:
    //一個 根,左,右 的路徑狀況有(根,左+根,根+右,左+根+右)
    //可是該根做爲其父親的孩子時,其max 應該爲 max(根,左+根,根+右).若是包含左+根+右,則加上其父親就構不成路徑了
    int maxPathSum(TreeNode* root) {
        long long gMax = LLONG_MIN;
        maxPathSumCore(root, gMax);
        return gMax;
    }

    int maxPathSumCore(TreeNode* root, long long& gMax){
        if(root==nullptr) return 0;
        int curVal = root->val;
        int leftMax = maxPathSumCore(root->left, gMax);
        int rightMax = maxPathSumCore(root->right, gMax);
        long long curMax = max(curVal, max(curVal+leftMax, max(curVal+rightMax, curVal+leftMax+rightMax)));
        if(curMax>gMax) gMax = curMax;
        return max(curVal, max(curVal+leftMax, curVal+rightMax));
    }
};

做者:lou-ding-_shai-tai-yang
連接:https://leetcode-cn.com/problems/binary-tree-maximum-path-sum/solution/di-gui-dang-qian-jie-dian-de-zui-da-lu-jing-he-dan/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

128. 最長連續序列

很簡便的作法,稍難理解

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        if(nums.empty()){
            return 0;
        }
        unordered_set<int> myset(nums.begin(), nums.end());
        int res = 0;
        
        for(auto num : nums){
            if(myset.count(num-1)==0){
                int x = num + 1;
                while(myset.count(x)){
                    x ++;
                }
                res = max(res, x-num);
            }
        }
        return res;
    }
};

做者:anyaleung
連接:https://leetcode-cn.com/problems/longest-consecutive-sequence/solution/cdai-ma-li-yong-unordered_set-by-anyaleung/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

129. 求根到葉子節點數字之和

字符串轉數字

int num = 0 ;
string s = "sdfsf";
num = std::atoi(s.c_str());
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
private:
vector<string> res;
string s;
public:
    void dfs(TreeNode* root)
    {
        if(!root->left && !root->right)
        {
            s = s + to_string(root->val);
            res.push_back(s);
            s.pop_back();
        }
        if(root->left)
        {
            s = s + to_string(root->val);
            dfs(root->left);
            s.pop_back();
        }
        if(root->right)
        {
            s = s + to_string(root->val);
            dfs(root->right);
            s.pop_back();
        }


    }
    int sumNumbers(TreeNode* root) {
        if(!root)return 0;
        dfs(root);
        int sum = 0;
        for(auto i:res)
        {
            sum += atoi(i.c_str());
        }
        return sum;
    }
};

130. 被圍繞的區域

本身寫的遞歸十分的複雜,主要問題在於,在判斷的過程當中就把不是本位置的元素給改了,致使路徑上發生變化,看了解答,發現是思路錯了,或者說這道題逆向思惟一下很是好作,就像數學選擇題裏面的舉反例同樣
被圍繞的區間不會存在於邊界上,換句話說,任何邊界上的 ‘O’ 都不會被填充爲 ‘X’。 任何不在邊界上,或不與邊界上的 ‘O’ 相連的 ‘O’ 最終都會被填充爲 ‘X’。若是兩個元素在水平或垂直方向相鄰,則稱它們是「相連」的。

做者:ZZYuting
連接:https://leetcode-cn.com/problems/surrounded-regions/solution/cbeats-9465easy-to-understand-by-zzyuting/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

/* First, check the four border of the matrix. If there is a element is 'O', alter it and all its nei***or 'O' elements to '1'. Then ,alter all the 'O' to 'X' At last,alter all the '1' to 'O' For example: X X X X X X X X X X X X X X O X -> X X O X -> X X X X X O X X X 1 X X X O X X X O X X X 1 X X X O X X */
class Solution {
public:
    void solve(vector<vector<char>>& board) {
        if(board.size()==0){
            return;
        }
        int rows=board.size(),cols=board[0].size();
        //對邊界上的進行dfs
        for(int i=0;i<rows;i++){
            dfs(board,i,0);
            dfs(board,i,cols-1);
        }
        for(int j=1;j<cols-1;j++){
            dfs(board,0,j);
            dfs(board,rows-1,j);
        }
        //遍歷所有的,1變0,其餘爲X,很巧妙的先把這些量都標出來來了
        for(int i=0;i<rows;i++){
            for(int j=0;j<cols;j++){
                if(board[i][j]=='1'){
                    board[i][j]='O';
                }
                else{
                    board[i][j]='X';
                }
            }
        }
    }
private:
    void dfs(vector<vector<char>>& board,int i,int j){
    	//若是既不在邊界上並且又爲X的直接跳過,當此邊界上的點爲0時纔有動做
    	//若是在邊界上爲O,就直接改爲1
        if(i>=0&&i<board.size()&&j>=0&&j<board[0].size()&&board[i][j]=='O'){
            board[i][j]='1';
            dfs(board,i-1,j);
            dfs(board,i+1,j);
            dfs(board,i,j-1);
            dfs(board,i,j+1);
        }
    }
};

做者:ZZYuting
連接:https://leetcode-cn.com/problems/surrounded-regions/solution/cbeats-9465easy-to-understand-by-zzyuting/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
在這裏插入代碼片

144. 二叉樹的前序遍歷

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution {
private:
vector<int> res;
public:
    void dfs(TreeNode* root)
    {
        if(root==NULL)return;
        res.push_back(root->val);
        dfs(root->left);
        dfs(root->right);
    }
    vector<int> preorderTraversal(TreeNode* root) {
        dfs(root);
        return res;
    }
};

146. LRU緩存機制

使用哈希map和雙鏈表:
邏輯

// key 映射到 Node(key, val)
HashMap<Integer, Node> map;
// Node(k1, v1) <-> Node(k2, v2)...
DoubleList cache;

int get(int key) {
    if (key 不存在) {
        return -1;
    } else {        
        將數據 (key, val) 提到開頭;
        return val;
    }
}

void put(int key, int val) {
    Node x = new Node(key, val);
    if (key 已存在) {
        把舊的數據刪除;
        將新節點 x 插入到開頭;
    } else {
        if (cache 已滿) {
            刪除鏈表的最後一個數據騰位置;
            刪除 map 中映射到該數據的鍵;
        } 
        將新節點 x 插入到開頭;
        map 中新建 key 對新節點 x 的映射;
    }
}

較簡化的版本

class LRUCache {
public:
    //刪除、查找、插入的複雜度都O(1)
    LRUCache(int capacity) {
        cap=capacity;
    } 
    int get(int key) {
        if(hashtable.count(key)==0) return -1;
        else//更新到表頭
        {
            auto iter = hashtable[key];//找到對應結點地址
            cache.splice(cache.begin(),cache,iter);//移動到鏈表頭
            return cache.begin()->second;//返回value
        }
    }
    
    void put(int key, int value) {
        if(hashtable.count(key)==0) {
            //若是容量到了,刪除尾部元素,再加上新結點
            if(cache.size()==cap)   {
                hashtable.erase(cache.back().first);
                cache.pop_back();
            }//直接添加
            cache.push_front(make_pair(key,value));
            hashtable[key]=cache.begin(); 
        }
        else {//若是插入相同key的元素,除了要移動,value也須要更新
            auto iter = hashtable[key];
            iter->second=value;//更新地址value
            cache.splice(cache.begin(),cache,iter);//移動到鏈表頭
            hashtable[key]=cache.begin();   //更新hashtable的value
        }
    }
    unordered_map<int,list<pair<int,int>>::iterator> hashtable;
    list<pair<int,int>> cache;//key value
    int cap=0;
};

/** * Your LRUCache object will be instantiated and called as such: * LRUCache* obj = new LRUCache(capacity); * int param_1 = obj->get(key); * obj->put(key,value); */

做者:tong-guai
連接:https://leetcode-cn.com/problems/lru-cache/solution/ha-xi-shuang-xiang-lian-biao-you-hua-ban-ben-by-to/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
class LRUCache {
public:
    LRUCache(int capacity) {
        _capacity = capacity;
    }
    
    int get(int key) {
        if(_map.count(key) != 0)
        {
            int ret = (*_map[key]).second;
            _list.erase(_map[key]);
            _list.push_front({key, ret});
            _map[key] = _list.begin();
            return ret;
        }
        else return -1;
    }
    
    void put(int key, int value) {
        if(_map.count(key) == 0)
        {
            if(_list.size() == _capacity)
            {
                int k = _list.back().first;
                _map.erase(_map.find(k));
                _list.pop_back();
            }
        }
        else{
            _list.erase(_map[key]);
            _map.erase(_map.find(key));
        }
        _list.push_front({key, value});
        _map[key] = _list.begin();
    }

private:
    unordered_map<int, list<pair<int, int>>::iterator> _map;
    list<pair<int, int>> _list;
    int _capacity;
};

/** * Your LRUCache object will be instantiated and called as such: * LRUCache* obj = new LRUCache(capacity); * int param_1 = obj->get(key); * obj->put(key,value); */

做者:ma-te-zai-wei-ma
連接:https://leetcode-cn.com/problems/lru-cache/solution/lruhuan-cun-ji-zhi-by-ma-te-zai-wei-ma/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

150. 逆波蘭表達式求值

用bool判斷第一個符號而且用一個值儲存結果是很麻煩的事,不如就一直將結果放在堆棧中

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<string> st;
        //bool flag = true;第一次遇到的符號須要特殊處理,用flag來表示是不是第一個
        for(auto token:tokens)
        {
            if(token=="+")
            {
                int t1 =atoi(st.top().c_str());
                st.pop();
                int t2 = atoi(st.top().c_str());
                st.pop();
                st.push(to_string(t1+t2));
            }
            else if(token=="-")
            {
                int t1 =atoi(st.top().c_str());
                st.pop();
                int t2 = atoi(st.top().c_str());
                st.pop();
                st.push(to_string(t2-t1));
            }
            else if(token=="*")
            {
                int t1 =atoi(st.top().c_str());
                st.pop();
                int t2 = atoi(st.top().c_str());
                st.pop();
                st.push(to_string(t1*t2));
            }
            else if(token=="/")
            {
                int t1 =atoi(st.top().c_str());
                st.pop();
                int t2 = atoi(st.top().c_str());
                st.pop();
                st.push(to_string(t2/t1));
            }
            else
            {
                st.push(token);
            }
        } 
        return atoi(st.top().c_str());
    }
};

152. 乘積最大子數組(dp)

解題思路
這題是求數組中子區間的最大乘積,對於乘法,咱們須要注意,負數乘以負數,會變成正數,因此解這題的時候咱們須要維護兩個變量,當前的最大值,以及最小值,最小值可能爲負數,但沒準下一步乘以一個負數,當前的最大值就變成最小值,而最小值則變成最大值了。

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int res = INT_MIN , imax = 1, imin =1;
        for(int i = 0 ; i< (int)nums.size() ;i++)
        {
            if(nums[i]<0)swap(imax,imin);
            imax = max(nums[i],imax*nums[i]);
            imin = min (nums[i],imin*nums[i]);
            res = max(res,imax);
        }
        return res;
    }
};

153. 尋找旋轉排序數組中的最小值

class Solution {
public:
    int findMin(vector<int>& nums) {
        if(nums[0]<=nums.back())return nums[0];
        int left = 0 , right = nums.size();
        while(left<right)
        {
            int mid = left+(right-left)/2;
            if(nums[mid]>=nums[0])
            {left=mid+1;}
            else
            {right=mid;}
        }
        return nums[left];
    }
};

155. 最小棧

使用兩個隊列,可是會超時

class MinStack {
private:
queue<int> q1;
queue<int> q2;
public:
    /** initialize your data structure here. */
    MinStack() {
        
    }
    
    void push(int x) {
        if(q1.empty()&&q2.empty())q1.push(x);
        else if(q1.empty())q2.push(x);
        else if(q2.empty())q1.push(x);
    }
    
    void pop() {
        if(q1.empty())
        {
            while(q2.size()>1)
            {
                q1.push(q2.front());
                q2.pop();
            }
            q2.pop();
        }
        else
        {
            while(q1.size()>1)
            {
                q2.push(q1.front());
                q1.pop();
            }
            q1.pop();
        }
    }
    
    int top() {
        int res;
        if(q1.empty())
        {
            while(q2.size()>1)
            {
                q1.push(q2.front());
                q2.pop();
            }
            res = q2.front();
            q1.push(q2.front());
            q2.pop();

        }
        else
        {
            while(q1.size()>1)
            {
                q2.push(q1.front());
                q1.pop();
            }
            res = q1.front();
            q2.push(q1.front());
            q1.pop();            
        }
        return res;
    }
    
    int getMin() {
        int res = INT_MAX;
        if(q1.empty())
        {
            while(!q2.empty())
            {
                res = min(res, q2.front());
                q1.push(q2.front());
                q2.pop();
            }
        }
        else
        {
            while(!q1.empty())
            {
                res = min(res,q1.front());
                q2.push(q1.front());
                q1.pop();
            }
        }        
        return res;
    }
};

/** * Your MinStack object will be instantiated and called as such: * MinStack* obj = new MinStack(); * obj->push(x); * obj->pop(); * int param_3 = obj->top(); * int param_4 = obj->getMin(); */

一個棧s存放數據,另外一個棧min存放前棧中最小的數據

class MinStack {
public:
    stack<int> s;//數據棧
    stack<int> min;//輔助棧
    /** initialize your data structure here. */
    MinStack() {
        
    }
    
    void push(int x) {
        s.push(x);
        if(min.empty()||x<=min.top())
        {
            min.push(x);
        }
    }
    
    void pop() {
        if(s.top()==min.top())
            min.pop();
        s.pop();
    }
    
    int top() {
        return s.top();
    }
    int getMin() {
        return min.top();
    }
};

做者:chenlele
連接:https://leetcode-cn.com/problems/min-stack/solution/zui-xiao-zhan-by-gpe3dbjds1/
來源:力扣(LeetCode)
著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。

162. 尋找峯值

直接作是不符合要求的,看到logN應該直接想到使用二分法

class Solution {
public:
    int findPeakElement(vector<int>& nums) {
        int len =nums.size();
        if(len==0 || len ==1) return 0;
        if(len==2)
        {
            int i = nums[0]>nums[1]? 0:1;
            return i;
        } 
        for(int i = 1 ; i<len-1 ;i++)
        {
            if(nums[i]>nums[i-1] && nums[i]>nums[i+1]) return i;
        }
        if(nums[0]>nums[1])return 0;
        if(nums[len-1]>nums[len-2])return len-1;
        return INT_MIN;

    }
};

以前作過一道兩數之和的,因此 在這裏面使用了查找法,凡是查找須要遍歷,因此這樣作會超時,更好的辦法是雙指針一個在前一個在後,這裏雙指針法更好的緣由是數組已經排序好了,,能夠有規律的縮小雙指針的範圍

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int len = numbers.size();
        for(int i = 0 ;i<len ;i++)
        {
            auto iter = find(numbers.begin()+i+1,numbers.end(), target- numbers[i]); 
            if( iter!=numbers.end())
            {
                int temp = iter-numbers.begin();
                vector<int> res={i+1,temp+1};
                return res;
            }
        }
        return {};
    }
};

169. 多數元素

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int len = nums.size();
        if(len==1) return nums[0];
        sort(nums.begin(),nums.end());
        return nums[len/2];
    }
};

179. 最大數

一開始想的是把全部數字都變成數組的形式,而後使用sort進行排序,可是會有一個問題,30和3進行比較的話確定會認爲30大而且在前,可是最後303顯然沒有330大,因此這種方法是有問題的

題目解析:根據題目中給的例子來看,主要就是要給給定數組進行排序,可是排序方法不是普通的升序或者降序,由於9要排在最前面,而9既不是數組中最大的也不是最小的,因此咱們要自定義排序方法。對於兩個數字a和b來講,若是將其都轉爲字符串,若是ab > ba,則a排在前面,好比9和34,因爲934>349,因此9排在前面,再好比說30和3,因爲303<330,因此3排在30的前面。按照這種規則對原數組進行排序後,將每一個數字轉化爲字符串再鏈接起來就是最終結果。
————————————————
版權聲明:本文爲CSDN博主「pushup8」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連接及本聲明。
原文連接:https://blog.csdn.net/pushup8/article/details/85196465

class Solution {
public:
    string largestNumber(vector<int>& nums) {
        string res = "";
        sort(nums.begin(), nums.end(), [](int a, int b){
            return to_string(a) + to_string(b) > to_string(b) + to_string(a);
        });
        for(auto num : nums){
            res += to_string(num); 
        }
        return res[0] == '0' ? "0" : res;
    }
};

本身寫的
注意sort函數重寫的四個要素1.static2.inline3.const4.&

class Solution {
public:
    static inline bool func(const string& a, const string& b)
    {
        return a+b>b+a;
    }
    string largestNumber(vector<int>& nums) {
        vector<string> st;
        //st.assign(nums.begin(),nums.end());
        for(auto i:nums)st.push_back(to_string(i));
        sort(st.begin(),st.end(),func);
        string res;
        for(auto i:st)res += i;
        while( (int)res.size()>1 && res[0]=='0')res = res.substr(1,(int)res.size()-1);
        return res;
    }
};

189. 旋轉數組

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int len = nums.size();
        reverse(nums.begin(),nums.end()-k%len
相關文章
相關標籤/搜索