文章目录
- 1. 最大子数组和【简单】
- 1.1 题目描述
- 1.2 解题思路
- 1.3 代码实现
- 2. 合并两个有序链表【简单】
- 2.1 题目描述
- 2.2 解题思路
- 2.3 代码实现
- 3. 两数之和【简单】
- 3.1 题目描述
- 3.2 解题思路
- 3.3 代码实现
- 4. 二叉树的层序遍历【中等】
- 4.1 题目描述
- 4.2 解题思路
- 4.3 代码实现
- 5. 最长回文子串【中等】
- 5.1 题目描述
- 5.2 解题思路
- 5.3 代码实现
1. 最大子数组和【简单】
题目链接:https://leetcode.cn/problems/maximum-subarray/
参考题解:https://leetcode.cn/problems/maximum-subarray/solution/zui-da-zi-xu-he-by-leetcode-solution/
1.1 题目描述
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例2:
输入:nums = [1]
输出:1
示例3:
输入:nums = [5,4,-1,7,8]
输出:23
提示:
- 1 <= nums.length <= 10^5
- -10^4 <= nums[i] <= 10^4
1.2 解题思路
动态规划,对于数组中的第i个元素,以其结尾的具有最大和的连续子数组一定是下面这两种情况之一:以第i-1个元素结尾的具有最大和的连续子数组加上第i个元素;第i个元素本身。为什么会有后一种情况呢?因为前一种情况可能会是负数,比如[-7,-1]这种情况,第1个元素其本身就要比第0个元素-7要大。
1.3 代码实现
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int pre = 0;
int ans = nums[0];
for (int i = 0; i < nums.size(); ++i) {
pre = max(pre + nums[i], nums[i]);
ans = max(pre, ans);
}
return ans;
}
};
2. 合并两个有序链表【简单】
题目链接:https://leetcode.cn/problems/merge-two-sorted-lists/
参考题解:https://leetcode.cn/problems/merge-two-sorted-lists/solution/he-bing-liang-ge-you-xu-lian-biao-by-leetcode-solu/
2.1 题目描述
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例2:
输入:l1 = [], l2 = []
输出:[]
示例3:
输入:l1 = [], l2 = [0]
输出:[0]
提示:
- 两个链表的节点数目范围是 [0, 50]
- -100 <= Node.val <= 100
- l1 和 l2 均按 非递减顺序 排列
2.2 解题思路
递归实现起来比较简单。如果l1值更小,那么可以递归地合并l1->next和l2。边界情况是某一个链表空了,直接把另一个链表接到结果后面就行了。
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;
}
else if (list2 == nullptr) {
return list1;
}
else if (list1 -> val < list2 -> val) {
list1 -> next = mergeTwoLists(list1 -> next, list2);
return list1;
}
else {
list2 -> next = mergeTwoLists(list1, list2 -> next);
return list2;
}
}
};
3. 两数之和【简单】
题目链接:https://leetcode.cn/problems/two-sum/
参考题解:https://leetcode.cn/problems/two-sum/solution/liang-shu-zhi-he-by-leetcode-solution/
3.1 题目描述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
- 2 <= nums.length <= 10^4
- -10^9 <= nums[i] <= 10^9
- -10^9 <= target <= 10^9
- 只会存在一个有效答案
3.2 解题思路
一个巧妙的思路是用哈希表把已经访问过的元素存下来,在访问下一个元素i时,查看目标值与当前元素i的差是不是在之前遍历过了,如果哈希表中有这样的元素j,那么 {i, j} 就是答案。
3.3 代码实现
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hash;
for(int i = 0; i < nums.size(); ++i) {
if (hash.count(target - nums[i])) {
return {i, hash[target - nums[i]]};
}
hash[nums[i]] = i;
}
return {-1, -1};
}
};
4. 二叉树的层序遍历【中等】
题目链接:https://leetcode.cn/problems/binary-tree-level-order-traversal/
参考题解:https://leetcode.cn/problems/binary-tree-level-order-traversal/solution/er-cha-shu-de-ceng-xu-bian-li-by-leetcode-solution/
4.1 题目描述
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
示例1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
示例2:
输入:root = [1]
输出:[[1]]
示例3:
输入:root = []
输出:[]
提示:
- 树中节点数目在范围 [0, 2000] 内
- -1000 <= Node.val <= 1000
4.2 解题思路
层序遍历是用队列来实现。每次把队首的节点弹出来,再把其左右节点加到队尾。每次往队尾加节点之前,队列中已有的所有节点,事实上就是位于树同一层的节点,所以每次把队列中所有已存节点出队,得到的就是一层的所有节点。可以在每次出队前记录下当前队列的长度,用一次循环实现,这样也就不会影响左右节点入队了。
4.3 代码实现
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector <vector <int>> ans;
if (root == nullptr) {
return ans;
}
queue<TreeNode*> q;
q.push(root);
while(!q.empty()) {
int len = q.size();
ans.push_back(vector <int> ());
for(int i = 0; i < len; ++i) {
ans.back().push_back(q.front() -> val);
if (q.front() -> left != nullptr) {
q.push(q.front() -> left);
}
if (q.front() -> right != nullptr) {
q.push(q.front() -> right);
}
q.pop();
}
}
return ans;
}
};
5. 最长回文子串【中等】
题目链接:https://leetcode.cn/problems/longest-palindromic-substring/
参考题解:https://leetcode.cn/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/
5.1 题目描述
给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
示例2:
输入:s = “cbbd”
输出:“bb”
提示:
- 1 <= s.length <= 1000
- s 仅由数字和英文字母组成
5.2 解题思路
对于字符串中的每个字符,可以考虑往两边不断尝试扩展,查看其左右字符是否相同。但是要注意可能会有连续两个字符相同的情况,也算回文,所以在调用扩展函数时要分别考虑i, i字符和i, i+1字符的扩展。
5.3 代码实现
class Solution {
public:
pair<int, int> expand(string s, int i, int j) {
while (i >= 0 && j < s.length() && (s[i] == s[j])) {
--i;
++j;
}
return {i + 1, j - 1};
}
string longestPalindrome(string s) {
int start = 0;
int end = 0;
for (int i = 0; i < s.length(); ++i) {
auto [left1, right1] = expand(s, i, i);
auto [left2, right2] = expand(s, i, i + 1);
if (right1 - left1 > end - start) {
start = left1;
end = right1;
}
if (right2 - left2 > end - start) {
start = left2;
end = right2;
}
}
return s.substr(start, end - start + 1);
}
};