2024届毕业生的刷题记录

  • LeetCode 热题 HOT 100
    • 两数之和
    • 两数相加
    • 无重复字符的最长子串
    • 寻找两个正序数组的中位数
    • 最长回文子串
    • N字形变换
    • 整数反转
    • 字符串转换整数
    • 回文数
    • 正则表达式匹配
    • 盛最多水的容器
    • 整数转罗马数字
    • 罗马数字转整数
    • 最长公共前缀
    • 三数之和
    • 最接近的三数之和
    • 电话号码的字母组合
    • 四数之和
    • 删除链表的倒数第 N 个结点
    • 有效的括号
    • 合并两个有序链表
    • 括号生成
    • 合并K个升序链表
    • 两两交换链表中的节点
    • K 个一组翻转链表
    • 删除有序数组中的重复项
    • 移除元素
    • 找出字符串中第一个匹配项的下标

开个博客来督促自己坚持每日一题~


LeetCode 热题 HOT 100

隔了好几个月没刷题了,没想到这个《LeetCode 热题 HOT 100》居然是会更新的,进度一下打回了 15/100 …

两数之和

描述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

思路
有手就会的题,直接遍历完事…但是如果想做到时间复杂度小于 O ( n 2 ) O(n^2) O(n2)的话,可以找个时间复杂度为 O ( n log ⁡ ( n ) ) O(n\log(n)) O(nlog(n))的算法派个序,再从头尾向中间寻找target就行了(和大了尾巴就往左边走,和小了头部就往右边走)。

代码

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

两数相加

描述
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 0 0 之外,这两个数都不会以 0 0 0 开头。

示例
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807

思路
有两个点要注意:(1)两个数不一样长;(2)进位问题,就算剩下一个数的时候,也要考虑进位的问题。

代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode *result = new ListNode();ListNode *now = new ListNode(0, result);int digit = 0, add = 0;while(l1 != nullptr && l2 != nullptr) {if(now->next == nullptr) {now->next = new ListNode();}now = now->next;int tmp_result = l1->val + l2->val + add;add = 0;if(tmp_result < 10) {now->val += tmp_result;}else {now->val += tmp_result - 10;add = 1;}l1 = l1->next;l2 = l2->next;++digit;}ListNode *left = nullptr;if(l1 != nullptr) {left = l1;} else if(l2 != nullptr) {left = l2;}while(left != nullptr) {if(now->next == nullptr) {now->next = new ListNode();}now = now->next;int tmp_result = left->val + add;add = 0;if(tmp_result < 10) {now->val += tmp_result;}else {now->val += tmp_result - 10;add = 1;}left = left->next;++digit;}if(add == 1) {now->next = new ListNode(1);}return result;}
};

无重复字符的最长子串

描述
给定一个字符串 s s s ,请你找出其中不含有重复字符的 最长子串 的长度。

示例
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

思路
有点类似于BM算法的思想。
(1)维护记录当前最长子串在原串中的左右下标;
(2)每次右下标向右移动一个字符,判断该字符是否在当前最长子串中出现过:
(2.a)如果没有出现,那么继续向右移;
(2.b)如果出现了,那么左下标就移动至该字符在当前最长子串中出现的位置的右侧,这样保证新的最长子串没有重复的字符;
(3)更新最长子串的长度。

代码

class Solution {public:int lengthOfLongestSubstring(string s) {// 检查输入if(s.size() == 0) {return 0;}// 寻找最长字串int left = 0, right = 1, maxLen = 1;while(right < s.size()) {string sub = s.substr(left, right - left);int index = sub.find(s[right]);if(index < 0 || index > sub.size()) {++right;}else {left += index + 1;++right;}sub = s.substr(left, right - left);if(sub.size() > maxLen) {maxLen = sub.size();}}return maxLen;}
};

寻找两个正序数组的中位数

描述
给定两个大小分别为 m m m 和 n n n 的正序(从小到大)数组 n u m s 1 nums1 nums1 和 n u m s 2 nums2 nums2。请你找出并返回这两个正序数组的 中位数

算法的时间复杂度应该为 O ( l o g ( m + n ) ) O(log (m+n)) O(log(m+n))。

示例
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3],中位数 2

思路
最简单、直接的思路是合并两个数组,但不用完全合并,只需要合并一半就行了。
最后输出的时候需要考虑总长度是奇数还是偶数。

代码

class Solution {public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {vector<int> nums;int mid_index = (nums1.size() + nums2.size()) / 2;int i1 = 0, i2 = 0;while(nums.size() < mid_index + 1) {if(i1 >= nums1.size()) {nums.push_back(nums2[i2]);++i2;}else if(i2 >= nums2.size()) {nums.push_back(nums1[i1]);++i1;}else {if(nums1[i1] >= nums2[i2]) {nums.push_back(nums2[i2]);++i2;}else {nums.push_back(nums1[i1]);++i1;}}}if((nums1.size() + nums2.size()) % 2 == 1) {return nums[mid_index];}else {return (nums[mid_index] + nums[mid_index - 1]) / 2.0;}}
};

标准答案
我的做法的时间复杂度和空间复杂度都会高一点,所以贴一下标准的思路吧。
题目是求中位数,其实就是求第 k 小数的一种特殊情况,而求第 k 小数有一种算法:由于数列是有序的,其实我们完全可以一半儿一半儿的排除。假设我们要找第 k 小数,我们可以每次循环排除掉 k/2 个数。

根据标准答案写的代码

class Solution {public:double findKthMinest(int k, vector<int>& nums1, vector<int>& nums2) {// 处理某一个数组为空的情况if(nums1.size() == 0) {return nums2[k - 1];}if(nums2.size() == 0) {return nums1[k - 1];}// 递归终止条件if(k == 1) {if(nums1[0] < nums2[0]) {return nums1[0];}else {return nums2[0];}}// 初始化二分法参数int i1 = 0, i2 = 0, index = k / 2 - 1;if(i1 + index >= nums1.size()) {i1 = nums1.size() - 1;}else {i1 = i1 + index;}if(i2 + index >= nums2.size()) {i2 = nums2.size() - 1;}else {i2 = i2 + index;}if(nums1[i1] <= nums2[i2]) {vector<int> new_nums1(nums1.begin() + i1 + 1, nums1.end());return findKthMinest(k - i1 - 1, new_nums1, nums2);}else {vector<int> new_nums2(nums2.begin() + i2 + 1, nums2.end());return findKthMinest(k - i2 - 1, nums1, new_nums2);}}double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int k = (nums1.size() + nums2.size()) / 2;if((nums1.size() + nums2.size()) % 2 == 0) {return (findKthMinest(k, nums1, nums2) + findKthMinest(k + 1, nums1, nums2)) / 2.0;}else {return findKthMinest(k + 1, nums1, nums2);}}
};

最长回文子串

描述
给你一个字符串 s s s,找到 s s s 中最长的回文子串。

如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。

示例
输入:s = "babad"
输出:"bab"
解释:"aba"同样是符合题意的答案。

思路
要注意回文串可能是奇数,也可能是偶数,这2种情况判断的方法还是略微有点不同的,因此我遍历数组的时候。

另外,解析里面提到了一种时间复杂度为 O ( n ) O(n) O(n) 的算法,但挺难的,希望笔面试都不会考到吧…

代码

class Solution {public:string longestPalindrome(string s) {string maxS = s.substr(0, 1);for(double i = 0.5; i < s.size(); i += 0.5) {// 回文串长度为偶数if(int(i) != i) {int li = int(i - 0.5), ri = int(i + 0.5);for(int j = 0; li - j >= 0 && ri + j < s.size(); ++j) {if(s[li - j] == s[ri + j]) {if(s.substr(li - j, (j + 1) * 2).size() > maxS.size()) {maxS = s.substr(li - j, (j + 1) * 2);}}else {break;}}}// 回文串长度为奇数else {int ii = int(i);for(int j = 1; ii - j >= 0 && ii + j < s.size(); ++j) {if(s[ii - j] == s[ii + j]) {if(s.substr(ii - j, j * 2 + 1).size() > maxS.size()) {maxS = s.substr(ii - j, j * 2 + 1);}}else {break;}}}}return maxS;}
};

N字形变换

描述
将一个给定字符串 s s s 根据给定的行数 n u m R o w s numRows numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "PAYPALISHIRING"行数为 3时,排列如下:

P         A         H       N
A    P    L    S    I    I   G
Y         I         R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

示例
输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"

思路
因为要输出所有字符,所以最小的时间复杂度也是 O ( n ) O(n) O(n)。
唯一有区别的就是时间复杂度,如果能够推导出每一行字符的规律,那么就无需借助额外的数组,但是我觉得不是很有必要来省这点空间复杂度。
另外要注意输出行数为1的极端情况。

代码

class Solution {public:string convert(string s, int numRows) {// Extreme conditionsif(numRows == 1) {return s;}// Initstring* rows = new string[numRows];for(int i = 0; i < numRows; ++i) {rows[i] = "";}// Convertint row = 0, dir = 1;for(int i = 0; i < s.size(); ++i) {rows[row] += s[i];row += dir;if(row == 0) {dir = -dir;}else if(row == numRows - 1) {dir = -dir;}}// Outputstring result = "";for(int i = 0; i < numRows; ++i) {result += rows[i];}delete[] rows;return result;}
};

整数反转

描述
给你一个 32 位的有符号整数 x x x ,返回将 x x x 中的数字部分反转后的结果。

如果反转后整数超过 32 32 32 位的有符号整数的范围 [ − 2 31 , 2 31 − 1 ] [−2^{31}, 2^{31} − 1] [−231,231−1] ,就返回 0 0 0。

提示:
假设环境不允许存储 64 位整数(有符号或无符号)。
− 2 31 < = x < = 2 31 − 1 -2^{31} <= x <= 2^{31} - 1 −231<=x<=231−1

示例
输入:x = -123
输出:-321

思路
整体不难,但是有好几个坑要注意:
(1)遇到负数的时候我们正常会把负号提取出来,然后把 x x x 转换为正整数处理,但是需要记住C++中 signed int负数范围是比正数范围要大的;
(2)C++中stringint的函数是stoi()intstring的函数是to_string()

代码

class Solution {public:int reverse(int x) {// Init and Extreme conditionsstring tmp = "", sign = "";if (x == 0 || x == -2147483648) {return 0;}else if (x < 0) {sign = "-";x = -x;}// Reversewhile (x > 0) {tmp += to_string(x % 10);x = x / 10;}// Delete the leading 0sfor (int i = 0; i < tmp.size(); ++i) {if (tmp[i] == '0') {continue;}else {tmp = tmp.substr(i, tmp.size() - i);break;}}// Determine whether the inverted integer exceeds 32 bitsif (tmp.length() == 10) {string bound;if (sign == "") {bound = "2147483647";}else {bound = "2147483648";}for (int i = 0; i < tmp.size(); ++i) {if (tmp[i] > bound[i]) {return 0;}else if (tmp[i] < bound[i]){break;}}}return stoi(sign + tmp);}
};

字符串转换整数

描述
请你来实现一个 myAtoi(string s)函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi函数)。

函数 myAtoi(string s)的算法如下:

  1. 读入字符串并丢弃无用的前导空格
  2. 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。 如果两者都不存在,则假定结果为正。
  3. 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  4. 将前面步骤读入的这些数字转换为整数(即,“123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 0 0 。必要时更改符号(从步骤 2 开始)。
  5. 如果整数数超过 32 32 32 位有符号整数范围 [ − 2 31 , 2 31 − 1 ] [−2^{31}, 2^{31} − 1] [−231,231−1] ,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −231 的整数应该被固定为 2 31 2^{31} 231 ,大于 2 31 − 1 2^{31} − 1 231−1 的整数应该被固定为 2 31 − 1 2^{31} − 1 231−1 。
  6. 返回整数作为最终结果。

注意:

  • 本题中的空白字符只包括空格字符 ' '
  • 除前导空格或数字后的其余字符串外,请勿忽略 任何其他字符。

示例
输入:s = "4193 with words"
输出:4193

思路
该题和上一题非常相似,只不过多了一个读取数字的操作而已。因为题目给出的算法步骤已经非常详细了,所以考验的更多的是编程能力以及对极限测试用例的判断。

代码

class Solution {public:int myAtoi(string s) {// 初始化int begin = 0;// 丢弃无用的前导空格while (s[begin] == ' ' && begin < s.size()) {++begin;}if (begin == s.size()) {return 0;}// 检查符号string sign = "";if (s[begin] == '-') {sign = "-";++begin;}else if(s[begin] == '+') {++begin;}if (begin == s.size()) {return 0;}// 读入数字int end = begin;while (s[end] - '0' >= 0 && s[end] - '0' <= 9) {++end;}// 没有数字则返回0if (end == begin) {return 0;}// 删除多余的0while(s[begin] == '0') {++begin;}// 截取整串数字string tmp = s.substr(begin, end - begin);if (tmp.size() == 0) {return 0;}// 判断整数数超过 32 位有符号整数范围, 是的话就截断if (tmp.length() > 10) {if (sign == "") {return 2147483647;}else {return -2147483648;}}else if (tmp.length() == 10) {string bound;if (sign == "") {bound = "2147483647";}else {bound = "2147483648";}for (int i = 0; i < tmp.size(); ++i) {if (tmp[i] > bound[i]) {return stoi(sign + bound);}else if (tmp[i] < bound[i]){break;}}}return stoi(sign + tmp);}
};

回文数

描述
给你一个整数 x x x ,如果 x x x 是一个回文整数,返回 true;否则,返回 false

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

例如, 121 121 121 是回文,而 123 123 123 不是。

示例
输入:x = -121
输出:false

思路
根据题目的要求:
(1) 负数肯定不是回文数;
(2) 0肯定是回文数;
(3) 正数的话要满足正序和倒序读都是一样的才是,最简单的就是之间转换成字符串来处理;

代码

class Solution {public:bool isPalindrome(int x) {if (x < 0) {return false;}else if (x == 0) {return true;}else {string s = to_string(x);int l = 0, r = s.size() - 1;while(l < r) {if (s[l] != s[r]) {return false;}++l;--r;}return true;}}
};

标准答案
因为在进阶要求里面,不允许借助字符串来实现这一程序,所以要换种思路,直接通过比较数字来判断是否属于回文数。
先考虑数字位数是偶数的情况,回文数即代表着数字后半部分反过来后要等于前半部分;再反观奇数的情况,其实最中间的数字是什么并不重要,我们要判断的还是去掉中间数字后数字后半部分反过来后是否等于前半部分。
因此我们要解决的问题就是如何将数字的后半部分反过来,并且如何知道反转数字的位数已经达到原始数字位数的一半?由于整个过程我们不断将原始数字除以 10,然后给反转后的数字乘上 10,所以,当原始数字小于或等于反转后的数字时,就意味着我们已经处理了一半位数的数字了。

正则表达式匹配

描述
给你一个字符串s和一个字符规律p,请你来实现一个支持'.''*'的正则表达式匹配。

  • '.'匹配任意单个字符;
  • '*'匹配零个或多个前面的那一个元素;

所谓匹配,是要涵盖 整个 字符串s的,而不是部分字符串。

思路
这题乍一看非常难,但是用递归的思路来解决,就会很清晰明了。
首先说一下递归的终止条件:

  • 字符串不为空、模式串为空,无法匹配,返回false
  • 字符串为空、模式串不为空,且模式串首模式不带有*,不可能匹配成功,返回false
  • 字符串和模式串都为空,匹配成功,返回true
  • 字符串首字符和模式串首模式不匹配,证明无法匹配,返回false

接下来就是如何递归了:

  • 模式串首模式是简单的字符,不包括'.''*',那么直接去掉字符串和模式串的首字符,进入下一层递归就可以了;
  • 模式串首模式包含了'.''*',那么就要继续分情况讨论了:
    – 只有'.',那么要往下匹配就只能用这个来匹配字符串首字符,所以直接去掉字符串和模式串的首字符,进入下一层递归就可以了;
    – 只有'*'和前一个字符,如果前一个字符可以匹配上字符串首字符,那么就进入去掉字符串首字符和模式串首模式、只去掉字符串首字符、只去掉模式串首模式这三种情况;如果前一个字符不能匹配上字符串首字符,那么就只进入去掉模式串首模式这种情况。

但是上面根据上面的思路直接做居然超出时间限制了!!!所以想一下怎么缩减时间复杂度。

首先从模式串本身入手,例如a*a*这种模式可以化简为a*,这样能省去很多不必要的时间开销。
(以上简化思路受到了没通过的测试用例的启发)

代码

class Solution {public:bool match(string s, string p) {// 递归终止条件if (s.size() == 0 && p.size() == 0) {return true;}if (s.size() != 0 && p.size() == 0) {return false;}if (s.size() == 0 && p.size() != 0) {if (p.size() > 1 && p[1] == '*') {return match(s, p.substr(2, p.size() - 2));}else {return false;}}// 开始递归if (p.size() > 1 && p[1] == '*') {if (s[0] == p[0] || p[0] == '.') {return match(s.substr(1, s.size() - 1), p.substr(2, p.size() - 2)) ||match(s.substr(1, s.size() - 1), p) ||match(s, p.substr(2, p.size() - 1));}else {return match(s, p.substr(2, p.size() - 2));}}else {if (s[0] == p[0] || p[0] == '.') {return match(s.substr(1, s.size() - 1), p.substr(1, p.size() - 1));}else {return false;}}}bool isMatch(string s, string p) {int index = 3;while (index < p.size()) {if (p[index] == '*') {if (p[index - 2] == '*') {// "a*a*" to "a*"if (p[index - 3] == p[index - 1]) {p = p.substr(0, index - 3) + p.substr(index - 1, p.size() - index + 1);index -= 2;}}}++index;}return match(s, p);}
};

盛最多水的容器

描述
给定一个长度为 n n n 的整数数组 height。有 n n n 条垂线,第 i i i 条线的两个端点是 (i, 0)(i, height[i])
找出其中的两条线,使得它们与 x x x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。

示例

思路
看题目给出的数据范围,直接采用双层循环来遍历肯定会超时(别问我为什么知道 ),所以要想一个巧妙的方法。
这题乍一看确实没想出比较好的做法,无奈只能看别人的答案了。
这题比较经典的做法是双指针法,首先假设数组最左和最右是目前容器的边界,那么基于V=min(height[i], height[j]) * (j - i)这个公式,如果我们移动这两个边界中长的一条,体积毫无疑问会减少;如果移动短的一条,体积可能会增大。所以每次都移动两条边界中短的那一条,记录每次是否超过最大体积,直到边界相遇就可以了。
应该没有人会问“为什么不同时移动两条边界”吧,因为这样会跳过一些容器,应该很容易理解。

代码

class Solution {public:int maxArea(vector<int>& height) {int maxV = 0, l = 0, r = height.size() - 1;while (l < r) {maxV = max(maxV, min(height[l], height[r]) * (r - l));if (height[l] < height[r]) {++l;} else {--r;}}return maxV;}
};

整数转罗马数字

描述
罗马数字包含以下七种字符: 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: num = 58
输出1: "LVIII"
解释1: L = 50, V = 5, III = 3.
输入2: num = 1994
输出2: "MCMXCIV"
解释2: M = 1000, CM = 900, XC = 90, IV = 4.

思路
因为罗马数字最多也就到千位,所以直接分成个十百千位来处理,虽然代码不是很美观,但是实用就行了;

代码

class Solution {public:string intToRoman(int num) {string re = "";int tmp = 0;// 个位tmp = num % 10;num /= 10;if (tmp < 4) {while (tmp--) {re += "I";}}else if (tmp == 4) {re += "IV";}else if (tmp < 9) {re += "V";tmp -= 5;while (tmp--) {re += "I";}}else {re += "IX";}if (num == 0) {return re;}// 十位tmp = num % 10;num /= 10;if (tmp < 4) {while (tmp--) {re = "X" + re;}}else if (tmp == 4) {re = "XL" + re;}else if (tmp < 9) {tmp -= 5;while (tmp--) {re = "X" + re;}re = "L" + re;}else {re = "XC" + re;}if (num == 0) {return re;}// 百位tmp = num % 10;num /= 10;if (tmp < 4) {while (tmp--) {re = "C" + re;}}else if (tmp == 4) {re = "CD" + re;}else if (tmp < 9) {tmp -= 5;while (tmp--) {re = "C" + re;}re = "D" + re;}else {re = "CM" + re;}if (num == 0) {return re;}// 千位tmp = num % 10;num /= 10;while (tmp--) {re = "M" + re;}return re;   }
};

罗马数字转整数

描述
罗马数字包含以下七种字符: 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: s = "LVIII"
输出1: "58"
解释1: L = 50, V = 5, III = 3.
输入2: “MCMXCIV”
输出2: 1994
解释2: M = 1000, CM = 900, XC = 90, IV = 4.

思路
因为罗马数字最多也就到千位,所以直接分成个十百千位来处理,虽然代码不是很美观,但是实用就行了;

代码

class Solution {public:int romanToInt(string s) {int index = 0, re = 0;// 千位while (s[index] == 'M') {re += 1000;++index;}// 百位if (s[index] == 'C') {if (index + 1 < s.size() && s[index + 1] == 'D') {re += 400;index += 2;}else if (index + 1 < s.size() && s[index + 1] == 'M') {re += 900;index += 2;}else {while (s[index] == 'C') {re += 100;++index;}}}else if (s[index] == 'D') {re += 500;++index;while (s[index] == 'C') {re += 100;++index;}}// 十位if (s[index] == 'X') {if (index + 1 < s.size() && s[index + 1] == 'L') {re += 40;index += 2;}else if (index + 1 < s.size() && s[index + 1] == 'C') {re += 90;index += 2;}else {while (s[index] == 'X') {re += 10;++index;}}}else if (s[index] == 'L') {re += 50;++index;while (s[index] == 'X') {re += 10;++index;}}// 个位if (s[index] == 'I') {if (index + 1 < s.size() && s[index + 1] == 'V') {re += 4;return re;}else if (index + 1 < s.size() && s[index + 1] == 'X') {re += 9;return re;}else {while (s[index] == 'I') {re += 1;++index;}}}else if (s[index] == 'V') {re += 5;++index;while (s[index] == 'I') {re += 1;++index;}}return re;}
};

最长公共前缀

描述
编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 ""

示例
输入:strs = ["flower","flow","flight"]
输出:"fl"

思路
遍历就完事了~

代码

class Solution {public:string longestCommonPrefix(vector<string>& strs) {string re = "";int i = 0;while(true) {if (i >= strs[0].size()) {return re;}char tmp = strs[0][i];for (int j = 1; j < strs.size(); ++j) {if (i >= strs[j].size() || strs[j][i] != tmp) {return re;}}re += tmp;++i;}return re;}
};

三数之和

描述
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]]满足 i != j、i != kj != k,同时还满足 nums[i] + nums[j] + nums[k] == 0。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组

示例
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0
不同的三元组是 [-1,0,1][-1,-1,2]
注意,输出的顺序和三元组的顺序并不重要。

思路
直接三重循环来找肯定会超时,遇到这种涉及数组的题目的时候,如果没有排序的一定要先排序,这样很大程度上可以将时间复杂度控制在 O ( n 2 ) O(n^2) O(n2) 或 O ( n l o g n ) O(nlogn) O(nlogn) 左右。
像这道题,先排序,然后遍历一遍数组,在每次遍历时再设置双指针,所以每次和大了右指针就往左走、和小了左指针就往右走,而且因为本身就是有序的,因此查重起来也方便很多。

代码

class Solution {public:vector<vector<int>> threeSum(vector<int>& nums) {// 排序sort(nums.begin(), nums.end());// 初始化vector<vector<int>> result;// 特殊情况if (nums[0] > 0 || nums[nums.size() - 1] < 0) {return result;}// 遍历for (int i = 0; i < nums.size(); ++i) {// 最小的数大于0了说明不可能有三数和为0if (nums[i] > 0) {break;}// 双指针模式可以充分利用数组有序这一条件int l = i + 1, r = nums.size() - 1;while (l < r) {if (nums[i] + nums[l] + nums[r] > 0) {--r;}else if (nums[i] + nums[l] + nums[r] < 0) {++l;}else {// 查重bool dumplicated = false;for (int j = result.size() - 1; j >= 0; --j) {if (result[j][0] != nums[i]) {break;}else if (result[j][1] == nums[l] && result[j][2] == nums[r]) {dumplicated = true;break;}}if (!dumplicated) {result.push_back(vector<int>({nums[i], nums[l], nums[r]}));}++l;--r;}}}return result;}
};

最接近的三数之和

描述
给你一个长度为 n n n 的整数数组 n u m s nums nums 和 一个目标值 t a r g e t target target。请你从 n u m s nums nums 中选出三个整数,使它们的和与 t a r g e t target target 最接近。
返回这三个数的和。

注意:假定每组输入只存在恰好一个解

示例
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2)

思路
这道题和上一道题“三数之和”基本上是一样的,先排序,然后遍历一遍数组,在每次遍历时再设置双指针,所以每次和大了右指针就往左走、和小了左指针就往右走。

代码

class Solution {public:int threeSumClosest(vector<int>& nums, int target) {// 排序sort(nums.begin(), nums.end());// 初始化int result = nums[0] + nums[1] + nums[2];// 特殊情况if (nums.size() == 3) {return result;}// 遍历for (int i = 0; i < nums.size(); ++i) {// 双指针模式可以充分利用数组有序这一条件int l = i + 1, r = nums.size() - 1;while (l < r) {int tmp = nums[i] + nums[l] + nums[r];if (abs(tmp - target) < abs(result - target)) {result = tmp;}if (tmp > target) {--r;}else if (tmp < target) {++l;}else {return target;}}}return result;}
};

电话号码的字母组合

描述
给定一个仅包含数字 2-9的字符串,返回所有它能表示的字母组合。答案可以按任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。


示例
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

思路
没什么难度的题目,就是把映射输入花费了点时间,为了代码简洁,采用了递归的写法。

代码

class Solution {public:vector<string> letterCombinations(string digits) {if (digits.size() == 0) {return vector<string>();}vector<string> num2char;if (digits[0] == '2') {num2char = {"a", "b", "c"};}else if (digits[0] == '3') {num2char = {"d", "e", "f"};}else if (digits[0] == '4') {num2char = {"g", "h", "i"};}else if (digits[0] == '5') {num2char = {"j", "k", "l"};}else if (digits[0] == '6') {num2char = {"m", "n", "o"};}else if (digits[0] == '7') {num2char = {"p", "q", "r", "s"};}else if (digits[0] == '8') {num2char = {"t", "u", "v"};}else if (digits[0] == '9') {num2char = {"w", "x", "y", "z"};}if (digits.size() == 1) {return num2char;}else {vector<string> tmp = letterCombinations(digits.substr(1, digits.size() - 1));vector<string> result;for (int i = 0; i < num2char.size(); ++i) {for (int j = 0; j < tmp.size(); ++j) {result.push_back(num2char[i] + tmp[j]);}}return result;}}
};

四数之和

描述
给你一个由 n n n 个整数组成的数组 nums,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]](若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abcd互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

示例
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

思路
两数之和 -> 三数之和 -> 四数之和…
思路和三数之和差不多,只不过多套了一层循环,相当于把四数之和降为三数之和处理。

不过这道题有一个大坑!!!

nums中数据的范围是 − 1 0 9 < = -10^9 <= −109<= nums[i] < = 1 0 9 <= 10^9 <=109,所以在算四数之和的时候是有可能超出int的范围的需要转换为double来处理!

代码

class Solution {public:vector<vector<int>> fourSum(vector<int>& nums, int target) {// 排序sort(nums.begin(), nums.end());// 初始化vector<vector<int>> result;// 特殊情况if (nums.size() < 4) {return result;}// 遍历for (int j = 0; j < nums.size(); ++j) {for (int i = j+ 1; i < nums.size(); ++i) {// 双指针模式可以充分利用数组有序这一条件int l = i + 1, r = nums.size() - 1;while (l < r) {double tmp = nums[j] + nums[i];tmp += nums[l] + nums[r];if (tmp > target) {--r;}else if (tmp < target) {++l;}else {// 查重bool dumplicated = false;for (int k = result.size() - 1; k >= 0; --k) {if (result[k][0] != nums[j]) {break;}else if (result[k][1] == nums[i] && result[k][2] == nums[l] && result[k][3] == nums[r]) {dumplicated = true;break;}}if (!dumplicated) {result.push_back(vector<int>({nums[j], nums[i], nums[l], nums[r]}));}++l;--r;}}}}return result;}
};

删除链表的倒数第 N 个结点

描述
给你一个链表,删除链表的倒数第 n n n 个结点,并且返回链表的头结点。

示例
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

思路
单向链表的缺点就在于不能倒序遍历而且无法按下标获取结点,所以最简单的做法就是把链表读取为数组就行了。

虽然上述思路通过了,这边还是贴一下正确思路吧。

维护两个指针指向头部,其中一个指针先走 n n n 步,然后另外那个指针再开始走,先走的指针到达尾部时,慢走的指针就刚好指在倒数第 n n n 个元素。

代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {public:ListNode* removeNthFromEnd(ListNode* head, int n) {// 用容器存储链表vector<ListNode*> list;ListNode* now = head;while (now != nullptr) {list.push_back(now);now = now->next;}// 特殊情况if (list.size() == 1) {return nullptr;}// 找到倒数第n个节点的下标int index = list.size() - n;// 删除(要分3种情况)if (index == 0) {return list[1];}else if (index == list.size() - 1) {list[index - 1]->next = nullptr;}else {list[index - 1]->next = list[index + 1];}return list[0];}
};

有效的括号

描述
给定一个只包括 '(',')','{','}','[',']'的字符串 s,判断字符串是否有效。

有效字符串需满足:

  • 左括号必须用相同类型的右括号闭合。
  • 左括号必须以正确的顺序闭合。
  • 每个右括号都有一个对应的相同类型的左括号

示例
输入:s = "()[]{}"
输出:true

思路
明显需要借助栈来解决:遇到左括号直接入栈;遇到右括号,检查栈是否为空或者栈顶元素是否位对应的左括号,不是的话直接返回false,是的话栈顶元素出栈。

代码

class Solution {public:bool isValid(string s) {stack<char> c;for(int i = 0; i < s.size(); ++i) {if (s[i] == '(' || s[i] == '[' || s[i] == '{') {c.push(s[i]);}else {if (s[i] == ')') {if (c.empty() || c.top() != '(') {return false;}else {c.pop();}}if (s[i] == ']') {if (c.empty() || c.top() != '[') {return false;}else {c.pop();}}if (s[i] == '}') {if (c.empty() || c.top() != '{') {return false;}else {c.pop();}}}}if (c.empty()) {return true;}else {return false;}}
};

合并两个有序链表

描述
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

示例
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

思路
如果是数组的话直接归并就行了,但是既然是链表的题目,那么考察的肯定是如果改变指针而不需要借助额外的空间。
因此,思路可以是固定第1个链表,把第2个链表内的元素插入到第1个链表的合适的位置。
这边要注意插入有3种情况:(1)插在最前面;(2)插在中间;(3)整个插在最后面。

代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {if (list1 == nullptr) {return list2;}if (list2 == nullptr) {return list1;}ListNode* pre1 = nullptr, *result = list1;while (list1 != nullptr && list2 != nullptr) {if (list1->val >= list2->val) {if (pre1 == nullptr) {ListNode* tmp2 = list2->next;list2->next = list1;result = list2;pre1 = list2;list2 = tmp2;}else {ListNode* tmp2 = list2->next;list2->next = list1;pre1->next = list2;pre1 = list2;list2 = tmp2;}}else {pre1 = list1;list1 = list1->next;}}if (list2 != nullptr) {pre1->next = list2;}return result;}
};

括号生成

描述
数字 n代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

思路
这道题看起来很简单,但其实有点坑的。
一开始我想这是3种情况的递归就能解决这个问题:
(1)"(" + generateParenthesis(n - 1) + ")"
(2)"()" + generateParenthesis(n - 1)
(3)generateParenthesis(n - 1) + "()"
但是提交上去后错了,而且苦思不得其解,最后翻了答案才发现是要用 (a)b, an + bn = n - 1这种形式来作为递归方程的。
我比较懒就没有记录中间状态,如果要进一步节省时间的话可以记录一下小于n的各种状态。

代码

class Solution {public:vector<string> generateParenthesis(int n) {// 递归终止条件if (n == 0) {return vector<string>({});}if (n == 1) {return vector<string>({"()"});}if (n == 2) {return vector<string>({"(())", "()()"});}if (n == 3) {return vector<string>({"((()))","(()())","(())()","()(())","()()()"});}// 以 (a)b 的形式构造当前可能的括号串vector<string> result;for (int an = 0; an <= n - 1; ++an) {int bn = n - an - 1;vector<string> a = generateParenthesis(an);vector<string> b = generateParenthesis(bn);if (a.empty()) {for (int bi = 0; bi < b.size(); ++bi) {result.push_back("()" + b[bi]);}}else if (b.empty()) {for (int ai = 0; ai < a.size(); ++ai) {result.push_back("(" + a[ai] + ")");}}else {for (int ai = 0; ai < a.size(); ++ai) {for (int bi = 0; bi < b.size(); ++bi) {result.push_back("(" + a[ai] + ")" + b[bi]);}}}}return result;}
};

合并K个升序链表

描述
给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例
输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]

思路
前面说到这种合并链表的题目时最好的方法肯定是不借助外部空间,直接对链表结点进行重新链接操作。
但是这道题目相对比较复杂,那么在笔试的过程中肯定是以稳重为主,所以直接老老实实把链表合并为数组,再转换为链表吧。

代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {public:ListNode* mergeKLists(vector<ListNode*>& lists) {// 特殊情况if (lists.empty()) {return nullptr;}if (lists.size() == 1) {return lists[0];}// 合并成升序数组vector<int> arrayResult;while (true) {int minV = 100000, minI = -1;for (int i = 0; i < lists.size(); ++i) {if (lists[i] != nullptr && lists[i] -> val < minV) {minV = lists[i]->val;minI = i;}}if (minI != -1) {arrayResult.push_back(minV);lists[minI] = lists[minI]->next;}else {break;}}// 转换为升序链表if (arrayResult.empty()) {return nullptr;}else {ListNode* result = new ListNode(arrayResult[0]);ListNode* current = result;for (int i = 1; i < arrayResult.size(); ++i) {current->next = new ListNode(arrayResult[i]);current = current->next;}return result;}}
};

两两交换链表中的节点

描述
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例
输入:head = [1,2,3,4,5]
输出:[2,1,4,3,5]

思路
既然要交换当前节点和上个节点,那么就要存储上上个节点、上个节点、当前节点和下个节点这4个中间变量。

代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {public:ListNode* swapPairs(ListNode* head) {// 特殊情况if (head == nullptr || head->next == nullptr) {return head;}// 交换第1组(因为涉及到头节点)ListNode* result = head->next;ListNode* pre = head;ListNode* current = head->next;ListNode* next = head->next->next;current->next = pre;pre->next = next;ListNode* prepre = current;current = next;// 交换余下组int i = 0;while (current != nullptr) {if (i) {next = current->next;prepre->next = current;current->next = pre;pre->next = next;prepre = current;current = next;--i;}else {prepre = pre;pre = current;current = current->next;++i;}}return result;}
};

K 个一组翻转链表

描述
给你链表的头节点 head,每 k个节点一组进行翻转,请你返回修改后的链表。

k是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]

思路
该题是上一题的拓展,可以把数组分为待翻转区域前、中、后部分,即利用 startend来记录翻转区域的首位置和末位置,用prenext来记录翻转区域的前一个位置和后一个位置。
这样,每次读取到k个元素后就进行一次翻转动作。翻转动作比较好实现,记录当前元素的上下两个元素,把当前元素指向上一个元素,然后当前元素等于下一个元素。

代码

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {public:ListNode* reverseKGroup(ListNode* head, int k) {// 不用翻转的情况if (k == 1) {return head;}// 虚假头节点ListNode* vHead = new ListNode(0, head);// 需要记录待翻转区域的前一个节点,第一个节点、最后一个节点和后一个节点ListNode* pre = vHead, * start = head, * end = head->next, * next;// 翻转int n = 2;while (end != nullptr) {if (n == k) {next = end->next;ListNode* currentPre = start, * current = start->next;for(int i = 1; i < k; ++i) {ListNode* tmp = current->next;current->next = currentPre;currentPre = current;current = tmp;}pre->next = end;start->next = next;pre = start;start = pre->next;end = start;n = 1;}else {end = end->next;++n;}}return vHead->next;}
};

删除有序数组中的重复项

描述
给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组 nums 的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。

将最终结果插入 nums 的前 k 个位置后返回 k 。

不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例
输入:nums = [1,2,2,3,4,5]
输出:5, nums = [1,2,3,4,5]

思路
因为我用的一直是C++,所以更多的是考察对vector的理解。
这边要注意使用erase函数删除vector里面的元素时,所有被删除元素之前的元素都会向前移一位,所以相当于迭代器会自动指向被删除的元素之后的元素。

代码

class Solution {public:int removeDuplicates(vector<int>& nums) {vector<int>::iterator it = nums.begin();++it;while(it != nums.end()) {if (*it == *(it - 1)) {nums.erase(it);}else {++it;}}return nums.size();}
};

移除元素

描述
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

示例
输入:nums = [1,2,2,3,4,5], val = 2
输出:4, nums = [1,3,4,5]

思路
因为我用的一直是C++,所以更多的是考察对vector的理解。
这边要注意使用erase函数删除vector里面的元素时,所有被删除元素之前的元素都会向前移一位,所以相当于迭代器会自动指向被删除的元素之后的元素。

代码

class Solution {public:int removeElement(vector<int>& nums, int val) {vector<int>::iterator it = nums.begin();while(it != nums.end()) {if (*it == val) {nums.erase(it);}else {++it;}}return nums.size();}
};

找出字符串中第一个匹配项的下标

描述
给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1 。

示例
输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad"在下标 06处匹配。第一个匹配项的下标是 0,所以返回 0

思路
模式串匹配那肯定是经典的KMP算法了,这个网上的资料挺多的,大家可以自行去搜索。

代码

class Solution {public:int strStr(string haystack, string needle) {// 计算模式串pattern的next数组// next[i] 表示: needle[0] ~ needle[i] 这一个子串,使得前k个字符恰等于后k个字符的最大的k// 特别地, k 不能取 i + 1(因为这个子串一共才 i + 1 个字符, 自己肯定与自己相等,就没有意义了)int* next = new int[needle.size()];next[0] = 0;    // next[0]必然是0, 因为只有 1 个字符int next_i = 1, next_j = 0;while(next_i < needle.size()) {if(needle[next_i] == needle[next_j]) {next[next_i] = next_j + 1;++next_i;++next_j;}else if(next_j != 0) {next_j = next[next_j - 1];}else {next[next_i] = 0;++next_i;}}// 开始使用next进行KMP算法int ti = 0, pi = 0;while(ti < haystack.size()) {// 若匹配到相同字符,则两个串都向前走if(haystack[ti] == needle[pi]) {++ti;++pi;}// 如果匹配失败,且模式串下标pi不在首位,则使用next数组决定模式串下标pi的新值else if(pi != 0) {pi = next[pi - 1];}// 如果匹配失败,且模式串下标pi在首位,则直接移动主串下标即可else {++ti;}// 判断是否匹配成功if(pi == needle.size()) {return ti - needle.size();}}return -1;}
};

2024届毕业生的刷题记录相关推荐

  1. BUUCTF刷题记录(7)

    文章目录 web [NPUCTF2020]ezinclude [NPUCTF2020]ReadlezPHP [GXYCTF2019]BabysqliV3.0 非预期1 非预期2 预期 [NCTF201 ...

  2. LeetCode刷题记录15——21. Merge Two Sorted Lists(easy)

    LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) 目录 LeetCode刷题记录15--21. Merge Two Sorted Lists(easy) ...

  3. LeetCode刷题记录14——257. Binary Tree Paths(easy)

    LeetCode刷题记录14--257. Binary Tree Paths(easy) 目录 前言 题目 语言 思路 源码 后记 前言 数据结构感觉理论简单,实践起来很困难. 题目 给定一个二叉树, ...

  4. LeetCode刷题记录13——705. Design HashSet(easy)

    LeetCode刷题记录13--705. Design HashSet(easy) 目录 LeetCode刷题记录13--705. Design HashSet(easy) 前言 题目 语言 思路 源 ...

  5. LeetCode刷题记录12——232. Implement Queue using Stacks(easy)

    LeetCode刷题记录12--232. Implement Queue using Stacks(easy) 目录 LeetCode刷题记录12--232. Implement Queue usin ...

  6. LeetCode刷题记录11——290. Word Pattern(easy)

    LeetCode刷题记录11--290. Word Pattern(easy) 目录 LeetCode刷题记录11--290. Word Pattern(easy) 题目 语言 思路 源码 后记 题目 ...

  7. LeetCode刷题记录10——434. Number of Segments in a String(easy)

    LeetCode刷题记录10--434. Number of Segments in a String(easy) 目录 LeetCode刷题记录9--434. Number of Segments ...

  8. LeetCode刷题记录9——58. Length of Last Word(easy)

    LeetCode刷题记录9--58. Length of Last Word(easy) 目录 LeetCode刷题记录9--58. Length of Last Word(easy) 题目 语言 思 ...

  9. LeetCode刷题记录8——605. Can Place Flowers(easy)

    LeetCode刷题记录8--605. Can Place Flowers(easy) 目录 LeetCode刷题记录8--605. Can Place Flowers(easy) 题目 语言 思路 ...

最新文章

  1. 运用python的方式_六、python 方法的使用
  2. 超参数优化 贝叶斯优化框架_mlmachine-使用贝叶斯优化进行超参数调整
  3. LVM逻辑卷详解及创建
  4. JAVA入门级教学之(异常的处理try...catch)
  5. JS将各值拼接JSON串小例
  6. java 的 provider_Java Provider.Service getProvider()用法及代码示例
  7. flash制作文字笔顺_教你如何给GIF动态图片加上文字
  8. 解决echarts官网打不开访问失败问题
  9. STM32连接摄像头知识积累
  10. vue实现div高度可拖拽
  11. 深入理解MySQL(2):详谈索引结构
  12. 人工智能时代对会计行业的改变与反思
  13. 30分钟java桌球小游戏_30分钟完成桌球小游戏项目
  14. 电脑的windows键已被停用解决方法
  15. 格密码LLL算法:如何解决最短向量SVP问题(3)(完结篇)
  16. MPB:原核微生物群落随机性和确定性装配过程的计算方法
  17. 发挥GPU强大动力的CG语言
  18. 通信原理学习笔记5-2:数字调制——连续相位和恒包络问题(非线性功放、连续相位CP FSK信号、最小频移键控MSK、GMSK)
  19. 怎样在旅途中拍出好看的照片
  20. mysql连接 xorm_go xorm连接数据库

热门文章

  1. 【热门主题:快乐海贼王动漫主题】
  2. 告警与恢复告警原理及实现
  3. C - Powered Addition
  4. TextField的圆边框
  5. Python状态机(transitions模块)
  6. HandsFree 开源项目
  7. 西门子S7通讯批量写入char数据
  8. CVPR2022 活体检测 Adaptive Transformers for Robust Few-shotCross-domain Face Anti-spoofing
  9. tf.segment_xxx系列函数测试
  10. upload-labs第一关