1.盛最多水的容器
给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
说明:你不能倾斜容器。
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
解题:
双指针法:
设两指针 i , j,指向的水槽板高度分别为 h[i] , h[j] ,此状态下水槽面积为 S(i, j) 。由于可容纳水的高度由两板中的 短板 决定,因此可得如下 面积公式 :
//盛最多水的容器,解法《双指针法》
int maxArea(vector<int>& height) {
int l = 0;//左边
int r = height.size() - 1;//右边
int ans = 0;//结果
while (l < r) {
int area = min(height[l], height[r]) * (r - l);//min(height[l], height[r])水的容量取决于最矮的那个
ans = max(ans, area);//取面积最大的,即容量最大
if (height[l] <= height[r]) {
++l;//数组下标移动
}
else {
--r;//数组下标移动
}
}
return ans;
}
验证:
int a[9] = {1,8,6,2,5,4,8,3,7};
//通过数组a的地址初始化,注意地址是从0到9(左闭右开区间)
vector<int> height(a, a+9);
cout<<"最大容量为:"<<maxArea(height)<<endl;
答案:
2. 最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
解题:
此解法为动态规划法
我们用 P(i,j)表示字符串 s的第 ii到 j个字母组成的串(下文表示成 s[i:j])是否为回文串:
这里的「其它情况」包含两种可能性:
• s[i, j] 本身不是一个回文串;
• i > j,此时 s[i, j]本身不合法。
动态规划的状态转移方程:
初始状态:
• dp[i][i]=1; //单个字符是回文串
• dp[i][i+1]=1 if s[i]=s[i+1]; //连续两个相同字符是回文串
//最长回文子串
string longestPalindrome(string s) {
int n = s.size();
if (n < 2) {
return s;
}
int maxLen = 1;
int begin = 0;
// dp[i][j] 表示 s[i..j] 是否是回文串
vector<vector<int>> dp(n, vector<int>(n));
// 初始化:所有长度为 1 的子串都是回文串
for (int i = 0; i < n; i++) {
dp[i][i] = true;
}
// 递推开始
// 先枚举子串长度
for (int L = 2; L <= n; L++) {
// 枚举左边界,左边界的上限设置可以宽松一些
for (int i = 0; i < n; i++) {
// 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
int j = L + i - 1;
// 如果右边界越界,就可以退出当前循环
if (j >= n) {
break;
}
if (s[i] != s[j]) {
dp[i][j] = false;
} else {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
}
// 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substr(begin, maxLen);
}
验证:
cout<<"最长回文子串:"<<longestPalindrome("babad")<<endl;
答案:
3.有效的括号
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
示例 :
输入:s = “()[]{}”
输出:true
解题:
栈:
我们遍历给定的字符串 s。当我们遇到一个左括号时,我们会期望在后续的遍历中,有一个相同类型的右括号将其闭合。由于后遇到的左括号要先闭合,因此我们可以将这个左括号放入栈顶。
当我们遇到一个右括号时,我们需要将一个相同类型的左括号闭合。此时,我们可以取出栈顶的左括号并判断它们是否是相同类型的括号。如果不是相同的类型,或者栈中并没有左括号,那么字符串 s 无效,返回False。为了快速判断括号的类型,我们可以使用哈希表存储每一种括号。哈希表的键为右括号,值为相同类型的左括号。
在遍历结束后,如果栈中没有左括号,说明我们将字符串 ss 中的所有左括号闭合,返回True,否则返回 False。
注意到有效字符串的长度一定为偶数,因此如果字符串的长度为奇数,我们可以直接返回False,省去后续的遍历判断过程。
解题:
//有效括号
bool isValid(string s) {
int n = s.size();
if (n % 2 == 1) {
return false;
}
unordered_map<char,char> pairs = {//所有括号类型
{')', '('},
{']', '['},
{'}', '{'}
};
stack<char> stk;//栈
for (char ch: s) {
if (pairs.count(ch)) {//迭代遍历
if (stk.empty() || stk.top() != pairs[ch]) {
return false;//迭代完成后比较
}
stk.pop();//匹配就出栈
}
else {
stk.push(ch);//遇到不一样的就入栈
}
}
return stk.empty();
}
验证:
cout<<"[()[]{}]是:"<<isValid("()[]{}") <<endl;
4. 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
解题:
枚举数组中的每一个数 x,寻找数组中是否存在 target - x。
当我们使用遍历整个数组的方式寻找 target - x 时,需要注意到每一个位于 x 之前的元素都已经和 x 匹配过,因此不需要再进行匹配。而每一个元素不能被使用两次,所以我们只需要在 x 后面的元素中寻找 target - x。
解题:
vector<int> twoSum(vector<int>& nums, int target)
{
int n = nums.size();//数组大小
for (int i = 0; i < n; ++i) {//两次循环
for (int j = i + 1; j < n; ++j) {
if (nums[i] + nums[j] == target) //进行比较
{
return {i, j};//返回下标
}
}
}
return {};
}
5.最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入:strs = [“flower”,“flow”,“flight”]
输出:“fl”
解题:
纵向扫描:
纵向扫描时,从前往后遍历所有字符串的每一列,比较相同列上的字符是否相同,如果相同则继续对下一列进行比较,如果不相同则当前列不再属于公共前缀,当前列之前的部分为最长公共前缀。
string longestCommonPrefix(vector<string>& strs) {
if (!strs.size()) {//判断是否为空
return "";
}
int length = strs[0].size();
int count = strs.size();
for (int i = 0; i < length; ++i) {//纵向扫描
char c = strs[0][i];
for (int j = 1; j < count; ++j) {
if (i == strs[j].size() || strs[j][i] != c) {
return strs[0].substr(0, i);//返回子串
}
}
}
return strs[0];
}
验证:
string s[]={"flower","flow","flight"};
vector<string> str(s,s+3);
cout<<"最长前缀:"<<longestCommonPrefix(str)<<endl;
结果:
来源:力扣(LeetCode)
链接:https://leetcode-cn.com