LeetCode題目算法彙總

1、兩數之和

給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和爲目標值的那 兩個 整數,並返回他們的數組下標。
你可以假設每種輸入只會對應一個答案。但是,你不能重複利用這個數組中同樣的元素。
示例:
給定 nums = [2, 7, 11, 15], target = 9
因爲 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
來源:力扣(LeetCode)

//C++
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> result(2,-1);
        map<int,int> a;
        for(int i=0;i<nums.size();i++){
            if(a.count(target-nums[i]) > 0){
                result[0] = a[target - nums[i]];
                result[1] = i;
                break;
            }
            a[nums[i]] = i;
        }
        return result;
    }
};
//C
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    int *a = NULL;
    for(int i = 0;i<numsSize-1;i++)
        for(int j = i+1;j<numsSize;j++){
            if(nums[i] + nums[j] == target){
                a = (int *)malloc(sizeof(int)*2);
                a[0] = i;
                a[1] = j;
                *returnSize = 2;
                return a;
            }
        }
    return a;
}
/*int* returnSize這個有啥用啊,多餘的嗎這是*/

2、兩數相加

給出兩個 非空 的鏈表用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式存儲的,並且它們的每個節點只能存儲 一位 數字。
如果,我們將這兩個數相加起來,則會返回一個新的鏈表來表示它們的和。
您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。
示例:
輸入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
輸出:7 -> 0 -> 8
原因:342 + 465 = 807

來源:力扣(LeetCode)

//C
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){    
    /*頭結點*/
    struct ListNode *pre = (struct ListNode *)malloc(sizeof(struct ListNode));
    pre->val = 0;
    pre->next = NULL;
    
    /*用來移動的節點*/
    struct ListNode *temp = pre;
        
    int curry = 0;//進位
    int sum = 0;//和
    
    while(l1!=NULL || l2!=NULL){
        int x = (l1 != NULL? l1->val:0);
        int y = (l2 != NULL? l2->val:0);
        sum = x+y+curry;
        curry = sum / 10;
        sum = sum % 10;  //大於10取個位
        
        /*保存新節點*/
        struct ListNode *p = (struct ListNode *)malloc(sizeof(struct ListNode));
        p->val = sum;
        p->next = NULL;
        temp->next = p;
        temp = temp->next;
        
        if(l1!=NULL)
            l1 = l1->next;
        if(l2!=NULL)
            l2 = l2->next;
    }
    
    /*最後一次相加存在進位*/
    if(curry){
        struct ListNode *pp = (struct ListNode *)malloc(sizeof(struct ListNode));
        pp->val = 1;
        pp->next = NULL;
        temp->next = pp;
    }
    return pre->next;
}
/*思路:一共定義4個節點,其中兩個做臨時使用而已,每次循環中將兩個鏈表的頭結點取出,作和,另外需要記錄是否進位
特別注意最後輸出時,要判斷最後一次相加是否有進位,有的話需要建立新的節點加入鏈表中
*/

3、無重複字符的最長子串

給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。

示例 1:

輸入: “abcabcbb”
輸出: 3
解釋: 因爲無重複字符的最長子串是 “abc”,所以其長度爲 3。
示例 2:

輸入: “bbbbb”
輸出: 1
解釋: 因爲無重複字符的最長子串是 “b”,所以其長度爲 1。
示例 3:

輸入: “pwwkew”
輸出: 3
解釋: 因爲無重複字符的最長子串是 “wke”,所以其長度爲 3。
請注意,你的答案必須是 子串 的長度,“pwke” 是一個子序列,不是子串。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters

class Solution {
public:
	int lengthOfLongestSubstring(string s) {
		map<char, int> a;
		int maxlen = 0;
		int start = 0;
		int end = 0;
		for (int i = 0; i<s.length(); i++, end++) {
			if (a.count(s[i]) == 0) {
				a[s[i]] = i;
				maxlen = max(end - start + 1, maxlen);
				continue;
			}
			else {
				map<char, int>::iterator iter = a.begin();
				iter = a.find(s[i]);
				if(iter->second + 1 > start) /*例子:abba*/
					start = iter->second + 1;
				a[s[i]] = i;
				maxlen = max(end - start + 1, maxlen);
				continue;
			}
		}
		return maxlen;
	}
};
/*這個很有必要會,常見
思路:將沒有出現的字符放到map容器中,順便記錄其在字符串中的位置,下次當發現字符串中有次字符,
則將start位置移動到記錄的該字符位置的後一個,但是之前要進行判斷,必須移動後的start位置要在沒移動之前的後面,否則不移動*/

5、最長迴文子串

給定一個字符串 s,找到 s 中最長的迴文子串。你可以假設 s 的最大長度爲 1000。

示例 1:

輸入: “babad”
輸出: “bab”
注意: “aba” 也是一個有效答案。
示例 2:

輸入: “cbbd”
輸出: “bb”

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/longest-palindromic-substring

class Solution {
public:
	string longestPalindrome(string s) {
		int start = 0;
        int end = 0;
        int maxlen = 0;
        for(int i = 0;i<s.length(); i++){
            int len1 = gotwoway(s,i,i);//奇數
            int len2 = gotwoway(s,i,i+1);//偶數
            maxlen = max(max(len1,len2),maxlen);
            if(maxlen > end-start+1){//調整start和end的位置,爲了返回子串
                start = i-(maxlen-1)/2;
                end = i+maxlen/2;
            }
        }
        return s.substr(start,maxlen);
	}
public:
    int gotwoway(string &s , int left , int right)
    {
        int L = left;
        int R = right;
        while(L >= 0 && R<s.length() && s[L] == s[R]){
            L--;
            R++;
        }
        return R-L-1;      
    }
};
/*注意: 函數substr可以從某個位置返回某長度的字符串
思路: 函數gotwoway的作用是找到s字符串當前中間位置的最大回文串大小,left和right表示的是s字符串某中軸左右兩個位置
在調用該函數時,考慮兩種情況 1、奇數迴文子串 2、偶數迴文子串*/

6、Z字型變換

將一個給定字符串根據給定的行數,以從上往下、從左到右進行 Z 字形排列。

比如輸入字符串爲 “LEETCODEISHIRING” 行數爲 3 時,排列如下:

L C I R
E T O E S I I G
E D H N
之後,你的輸出需要從左往右逐行讀取,產生出一個新的字符串,比如:“LCIRETOESIIGEDHN”。

請你實現這個將字符串進行指定行數變換的函數:

string convert(string s, int numRows);
示例 1:

輸入: s = “LEETCODEISHIRING”, numRows = 3
輸出: “LCIRETOESIIGEDHN”
示例 2:

輸入: s = “LEETCODEISHIRING”, numRows = 4
輸出: “LDREOEIIECIHNTSG”
解釋:

L D R
E O E I I
E C I H N
T S G

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/zigzag-conversion

class Solution {
public:
    string convert(string s, int numRows) {
        string result;
        vector<string> a(min(numRows,(int)s.size()));
        bool isdowm = false;
        int temp = 0;
        if(numRows == 1){
            result = s;
            return result;
        } 
        for(char c : s){
            a[temp] += c;
            if(temp == 0 || temp == numRows -1)
                isdowm = !isdowm;
            temp += isdowm? 1 : -1;
        }
        for(string b : a)
            result += b;
        return result;
    }
};
//注意:for(char c : s)這個語法表示在s中遍歷每一個字符給c,全部遍歷完退出循環
//思路:定義一個vector容器,容器中存放的是Z字型的每一行的內容,
//定義isdowm和temp用來向下或向上依次將字符存放在容器的相應位置

7、判斷迴文數

判斷一個整數是否是迴文數。迴文數是指正序(從左向右)和倒序(從右向左)讀都是一樣的整數。

示例 1:

輸入: 121
輸出: true
示例 2:

輸入: -121
輸出: false
解釋: 從左向右讀, 爲 -121 。 從右向左讀, 爲 121- 。因此它不是一個迴文數。
示例 3:

輸入: 10
輸出: false
解釋: 從右向左讀, 爲 01 。因此它不是一個迴文數。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/palindrome-number

bool isPalindrome(int x){
    const int y = x;
    int temp = 0;
    long z = 0;
    if(x < 0)/*按照題目意思,負數不可能滿足迴文數*/
        return false;
    while(x != 0)
    {
        temp = x%10;
        x /= 10;  /*相比 x = x/10 可以加快執行時間*/ /*這句話待定,發現力扣的時間計算不太對,同樣的程序執行兩次時間上會不一樣*/
        z = temp + z*10;
    }
    if(z == y)
        return true;
    return false;
}

8、盛最多水的容器

給定 n 個非負整數 a1,a2,…,an,每個數代表座標中的一個點 (i, ai) 。在座標內畫 n 條垂直線,垂直線 i 的兩個端點分別爲 (i, ai) 和 (i, 0)。找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。

說明:你不能傾斜容器,且 n 的值至少爲 2。

圖中垂直線代表輸入數組 [1,8,6,2,5,4,8,3,7]。在此情況下,容器能夠容納水(表示爲藍色部分)的最大值爲 49。

在這裏插入圖片描述
示例:

輸入: [1,8,6,2,5,4,8,3,7]
輸出: 49

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/container-with-most-water

/*這個是雙指針發,其實雙指針就是表示兩個位置而已不是很難得東西*/
/*暴力破解直接將每個組可能性都輪訓,方法可行可惜過不了時間限制*/
/*暴力法*/
/*
class Solution {
public:
    int maxArea(vector<int>& height) {
        int f_water=0;
        for(int i=0;i<height.size();i++)
        {
            for(int j=i+1;j<height.size();j++)
            {
                int h=min(height[i],height[j]);
                int water=h*(j-i);
                f_water=max(f_water,water);
            }
        }
        return f_water;
    }
};

*/
class Solution {
public:
    int maxArea(vector<int>& height) {
        int f_water = 0;/* f 代表finaly,也就是最終的值^_^ */
        int i = 0;
        int j = height.size()-1;
        while(i<j)
        {
            int w = j-i;
            int h =min(height[i],height[j]);
            f_water = max(f_water,h*w);
            if(height[i] < height[j])
                i++;
            else 
                j--;
        }
        return f_water;
    }
};

在力扣有大神嚴謹的證明了雙指針方法的正確性,非常嚴謹,嚴謹到看的不是很明白…簡單說說我的理解爲什麼雙指針是可行的方法:
1、我們爲了求出最大的面積,就是儘量找對大的寬度和高度
2、但是我們的高度,是由兩者中較小的那個決定的,所以我們這麼想,我一開始將兩個指針放在開始和末尾,就是不管3721先把寬度弄到最大,然後求一次面積,這時候你想想,我們求出來的這個面積就是你無論此時怎麼移動長的指針(長指針就是高度較高的那個指針指的位置)都不可能超過的值了(因爲高度小的決定面積大小,而寬度已經最大
3、所以我們移動短指針,然後再求一次,這時再求出的值又是這種情況下不管怎麼移動長指針都超不過的最大值
4一次類推,就可以找到最大的值
所以雙指針只是巧妙的幫我們過濾掉了很多可以預見的不可能超過當前值得計算,大大減少時間。

9、整數轉羅馬數字

/*列舉的方法,把可能出現的情況全部準備好放到數組中去*/
class Solution {
public:
    string intToRoman(int num) {
        string result;
        int a[13] = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
        string b[13] = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
        for(int i = 0;i<13;i++)
        {
            while(num >= a[i])
            {
                num = num - a[i];
                result = result + b[i];
            }
        }
        return result;  
    }
};
/*這是尼瑪評論區一個鬼才的算法,人才....*/
char * intToRoman(int num){
    char * ret = NULL;
    if (num <= 0 || num > 3999) return ret;
    ret = (char *) malloc (sizeof(char) * 16);
    if (ret == NULL) {
        printf("申請內存出錯");
        exit(0);
    }
    ret[15] = 0; // memset(ret, 0, 16);
    
    char Rome[] = {'I', 'V', 'X', 'L', 'C', 'D', 'M'};
    char i = 14, j = 0, m = 0;
    
    while(num) {
        m = num % 10;
        num /= 10;
        while (1) {
            if (m == 9) {ret[i--] = Rome[j+2]; m = 1;}
            else if (m == 8) {ret[i--] = Rome[j]; m--;}
            else if (m == 7) {ret[i--] = Rome[j]; m--;}
            else if (m == 6) {ret[i--] = Rome[j]; m--;}
            else if (m == 5) {ret[i--] = Rome[j+1]; break;}
            else if (m == 4) {ret[i--] = Rome[j+1]; m=1;}
            else if (m == 3) {ret[i--] = Rome[j]; m--;}
            else if (m == 2) {ret[i--] = Rome[j]; m--;}
            else if (m == 1) {ret[i--] = Rome[j]; break;}
            else break;
        }
        j += 2;
    }
    return (ret + i + 1);/*牛批這個*/
}

10、羅馬數字轉整數

羅馬數字包含以下七種字符: I, V, X, L,C,D 和 M。

字符 數值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 羅馬數字 2 寫做 II ,即爲兩個並列的 1。12 寫做 XII ,即爲 X + II 。 27 寫做 XXVII, 即爲 XX + V + II 。

通常情況下,羅馬數字中小的數字在大的數字的右邊。但也存在特例,例如 4 不寫做 IIII,而是 IV。數字 1 在數字 5 的左邊,所表示的數等於大數 5 減小數 1 得到的數值 4 。同樣地,數字 9 表示爲 IX。這個特殊的規則只適用於以下六種情況:

I 可以放在 V (5) 和 X (10) 的左邊,來表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左邊,來表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左邊,來表示 400 和 900。
給定一個羅馬數字,將其轉換成整數。輸入確保在 1 到 3999 的範圍內。

示例 1:

輸入: “III”
輸出: 3
示例 2:

輸入: “IV”
輸出: 4

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/roman-to-integer

int read(char a){
    switch (a){
        case 'I': return 1;
        case 'V': return 5;
        case 'X': return 10;
        case 'L': return 50;
        case 'C': return 100;
        case 'D': return 500;
        case 'M': return 1000;
        default:  return 0;
    }
}
int romanToInt(char * s){
    int i = 0;
    int result = 0;
    while(s[i] != '\0')
    {
        int j = i+1;
        /*思路主要在這,一次我們判斷兩個字符,若是第一個小於第二個,則認爲出現特殊情況,處理後字符串跳兩個*/
        if(read(s[i]) < read(s[j])){
            result = result + (read(s[j]) - read(s[i]));
            i += 2;
        }
        else{/*這裏則是正常情況,字符串跳一個*/
            result = result + read(s[i]);
            i++;
        }  
    }
    return result;
}


11、最長公共前綴

編寫一個函數來查找字符串數組中的最長公共前綴。

如果不存在公共前綴,返回空字符串 “”。

示例 1:

輸入: [“flower”,“flow”,“flight”]
輸出: “fl”
示例 2:

輸入: [“dog”,“racecar”,“car”]
輸出: “”
解釋: 輸入不存在公共前綴。
說明:

所有輸入只包含小寫字母 a-z 。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/longest-common-prefix

/*這裏提醒自己一開始犯的錯誤,注意題目說的是公共前綴,是前綴,所以纔可以找到最短的字符串開始比較!*/
/*若是判斷兩個字符串的最大的公共部分,感覺難度就很大了*/
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        string min = "";
        if(strs.empty()){
            return min;
        }
        min = strs[0];
        /*循環比較多可能看的比較亂,邏輯就是先找到最小的那個字符串,再將最小字符串的每一個字符和剩下字符串的每一個字符比較*/
        for(int i = 1;i < strs.size();i++){
            if(min.size() > strs[i].size()) 
                min = strs[i];
        }
        for(int j = 0;j < min.size();++j){
            for(int k = 0;k < strs.size();k++){
                if(min[j] != strs[k][j])
                    return min.substr(0,j);
            }
        }
        return min;
    }
};

12、三數之和

給定一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?找出所有滿足條件且不重複的三元組。

注意:答案中不可以包含重複的三元組。

例如, 給定數組 nums = [-1, 0, 1, 2, -1, -4],

滿足要求的三元組集合爲:
[
[-1, 0, 1],
[-1, -1, 2]
]

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/3sum

/*學習了,我除了暴力法想不到什麼好的方法,這個是借鑑別人的思路*/
/*有個意識,就是在對數據處理之前,若是對數據進行一下排序,後期再處理就可以嘗試加快速度的算法了。	!排序 排序 排序!*/
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        if(nums.size() < 3){	/*小於3個,直接再見*/
            return result;
        }
        sort(nums.begin(),nums.end());
        for(int i = 0;i<nums.size()-2;i++){
            if(nums[i] > 0){
                return result;/*排序後,這裏應該是將要放進容器三個數中最小的一個,若是最小的都大於0了,就可以再見了*/
            }
            int j = i+1;
            int k = nums.size()-1;
            while(j<k)
            {
            	/*最小的兩個數+最大的一個數,若是大於0,將最大的數減小一個*/
                if(nums[i] + nums[j] + nums[k] > 0){
                    k--;
                }
                /*最小的兩個數+最大的一個數,若是小於0,將第二小那個數加大一個(因爲我們將遍歷最小的數)*/
                else if(nums[i] + nums[j] + nums[k] < 0){
                    j++;
                }
                /*相加 = 0*/
                else{
                    result.push_back(vector<int>{nums[i],nums[j],nums[k]});
                    /*這裏主要是相同的數我們跳過,在上面兩個條件中我們也可以同時進行該while判斷,*/
                    while(j<nums.size()-2 && nums[j] == nums[j+1])
                    {
                        j++;
                    }
                    j++;
                }
            }
            /*這裏主要是相同的數我們跳過*/
            while(i<nums.size()-2 && nums[i] == nums[i+1])
            {
                i++;
            }
        }  
        return result;
    }
};

13、最接近的三數之和

給定一個包括 n 個整數的數組 nums 和 一個目標值 target。找出 nums 中的三個整數,使得它們的和與 target 最接近。返回這三個數的和。假定每組輸入只存在唯一答案。

例如,給定數組 nums = [-1,2,1,-4], 和 target = 1.

與 target 最接近的三個數的和爲 2. (-1 + 2 + 1 = 2).

/*這個地方和上面那個8、盛最多水的容器有點像,都是通過先排序,再通過指針從開始和末尾依次移動,每次判斷大於小於決定移動開始的指針,還是末尾的指針
當然,這裏是三個數求和,所有多了一個指針,這個指針(變量tree)必須遍歷一遍nums,也是沒有辦法的了*/
class Solution {
public:
    int threeSumClosest(vector<int>& nums, int target) {
        int result_temp = INT_MAX;
        int result = 0;
        int len = nums.size();
        int tree = 0;
        sort(nums.begin(),nums.end());
        while(tree < len-2)
        {
            int begin = tree+1;
            int end = len -1;
            while(begin < end)
            {
                int x = nums[tree] + nums[begin] + nums[end];
                int a = abs(x - target);
                if(a < result_temp){
                    result = x;
                    result_temp = a;
                }
                if(a == 0)
                    return target;
                if(x > target)
                    end--;
                if(x < target)
                    begin++;
            }
            tree++;
        }
        return result;
    }
};

14、電話號碼的字母組合

給定一個僅包含數字 2-9 的字符串,返回所有它能表示的字母組合。

給出數字到字母的映射如下(與電話按鍵相同)。注意 1 不對應任何字母。
在這裏插入圖片描述
示例:

輸入:“23”
輸出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
說明:
儘管上面的答案是按字典序排列的,但是你可以任意選擇答案輸出的順序。

/*參考各路大神的答案*/
class Solution {
public:
    vector<string> letterCombinations(string digits) {
        vector<string> a{"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
        vector<string> c;
        if(digits.empty())
            return c;
        c.push_back(""); 	/*使得 c.size() == 1*/
        for(int i = 0;i<digits.size();i++){
            int where = digits[i] - '2';
            int len = c.size();
            for(int j = 0;j<len;j++){
                for(char cc : a[where] ){
                    c.push_back(c[j] + cc); /*在已有的每個字符串後面都追加上新的字符*/
                }
            }
            c.erase(c.begin(),c.begin() + len);
        }
        return c;
    }
};

15、四數之和

給定一個包含 n 個整數的數組 nums 和一個目標值 target,判斷 nums 中是否存在四個元素 a,b,c 和 d ,使得 a + b + c + d 的值與 target 相等?找出所有滿足條件且不重複的四元組。

注意:

答案中不可以包含重複的四元組。

示例:

給定數組 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

滿足要求的四元組集合爲:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]

/*一個下午就寫了這個,都怪小米5G發佈會*/

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        set<vector<int>> x;
        int treea = 0;
        int treeb = 0;
        int begin,end = 0;
        sort(nums.begin(),nums.end());
        int len = nums.size();
        while(treea < len-3 )
        {
            treeb = treea + 1;
            while(treeb < len-2)
            {
                begin = treeb + 1;
                end = len - 1;
                while(begin < end)
                {
                   int sum = nums[treea] + nums[treeb] + nums[begin] + nums[end];
                   if(sum < target){
                       begin++;
                   } 
                   else if(sum > target){
                       end--;
                   }
                   else if(sum == target){
                       vector<int> temp {nums[treea],nums[treeb],nums[begin],nums[end]};
                       x.insert(temp);
                       begin++;
                       end--;
                   }
                }
                treeb++;
            }   
            treea++;
        }
        for(vector<int>  m :  x){
            result.push_back(m);
        }
        return result;
    }
};

16、刪除鏈表的倒數第N個節點

給定一個鏈表,刪除鏈表的倒數第 n 個節點,並且返回鏈表的頭結點。

示例:

給定一個鏈表: 1->2->3->4->5, 和 n = 2.

當刪除了倒數第二個節點後,鏈表變爲 1->2->3->5.
說明:

給定的 n 保證是有效的。

/*
	這個我的想法也很簡單,就是像截取刪除字符串後面的字符一樣,先求出總的長度,
	再用總長度減去你要的倒數第幾個,就可以知道你要刪除的節點的具體位置了,接着就是常規刪節點操作,
	不過這裏不需要釋放內存空間,所以也省了一個臨時指針變量
*/
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    if(head == NULL)
        return NULL;
    struct ListNode* my_head = head;

    struct ListNode* temp = head;
    int temp3 = 0;
    //struct ListNode* temp2 = NULL;
    int len = 1;
    
    while(head->next != NULL) /*循環求出鏈表長度*/
    {
        head = head->next;
        len++;
    }
    if(len == n) /*這裏是一個特殊情況*/
    {
        return my_head->next;
    } 
    temp3 = len-n-1;
 
    while(temp3 > 0) /*通過循環把指針指向待刪除的節點的前一個*/
    {
        temp = temp->next;
        temp3--;
    }
     temp->next = temp->next->next;
    return my_head; 
}


17、有效的括號

給定一個只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判斷字符串是否有效。

有效字符串需滿足:

左括號必須用相同類型的右括號閉合。
左括號必須以正確的順序閉合。
注意空字符串可被認爲是有效字符串。

示例 1:
輸入: “()”
輸出: true
示例 2:
輸入: “()[]{}”
輸出: true
示例 3:
輸入: “(]”
輸出: false
示例 4:
輸入: “([)]”
輸出: false
示例 5:
輸入: “{[]}”
輸出: true

bool isValid(char * s){
        char stack[10240] = {0};
        int top = 0;
        int len = strlen(s);
        if(s[0] == ')' || s[0] == ']' || s[0] == '}')
            return false;
        for(int i = 0;i<len;i++){
            switch (s[i])
            {
                case '{':
                    stack[top++] = s[i];
                    break;
                case '[':
                    stack[top++] = s[i];
                    break;
                case '(':
                    stack[top++] = s[i];
                    break;
/**********************************/
                case '}':
                    top--;
                    if(top < 0)
                        return false;
                    if(stack[top] != '{'){
                        return false;
                    }
                    break;
                case ']':
                    top--;
                    if(top < 0)
                        return false;
                    if(stack[top] != '['){
                        return false;
                    }
                    break;
                case ')':
                    top--;
                    if(top < 0)
                        return false;
                    if(stack[top] != '('){
                        return false;
                    }
                    break;
                default:
                    return false;
            }
        }
    return (top ? false : true);
}

/*這個是別人的短一點的C代碼,原理相同*/
bool isValid(char * s){
    if (s == NULL || s[0] == '\0') return true;
    char stack[10240]; int top =0;
    for (int i = 0; s[i]; ++i) {
        if (s[i] == '(' || s[i] == '[' || s[i] == '{') stack[top++] = s[i];
        else {
            if ((--top) < 0)                      return false;//先減減,讓top指向棧頂元素
            if (s[i] == ')' && stack[top] != '(') return false;
            if (s[i] == ']' && stack[top] != '[') return false;
            if (s[i] == '}' && stack[top] != '{') return false;
        }
    }
    return (top ? false : true);//防止“【”這種類似情況
}


18、合併兩個有序鏈表

將兩個有序鏈表合併爲一個新的有序鏈表並返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成的。

示例:

輸入:1->2->4, 1->3->4
輸出:1->1->2->3->4->4

/*
	遞歸的巧妙運用。遞歸,遞歸,遞歸,什麼神仙思維
*/
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    if(l1 == NULL)
        return l2;
    else if(l2 == NULL)
        return l1;
    else if(l1->val < l2->val){
        l1->next = mergeTwoLists(l1->next,l2);
        return l1;
    }
    else if(l1->val >= l2->val){
        l2->next = mergeTwoLists(l1,l2->next);
        return l2;
    }
    return NULL;
}


在這裏插入圖片描述
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章