力扣简单算法(1)

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值