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:

扫描二维码关注公众号,回复: 11095930 查看本文章

输入: “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;
}


在这里插入图片描述
在这里插入图片描述

发布了46 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42718004/article/details/97753346