Category Archives: LeetCode

LeetCode Construct Binary Search Tree from Preorder Traversal

1008. Construct Binary Search Tree from Preorder Traversal

Return the root node of a binary search tree that matches the given preorder traversal.

(Recall that a binary search tree is a binary tree where for every node, any descendant of node.left has a value < node.val, and any descendant of node.right has a value > node.val.  Also recall that a preorder traversal displays the value of the node first, then traverses node.left, then traverses node.right.)

Example 1:

Input: [8,5,1,7,10,12]
Output: [8,5,10,1,7,null,12]

Note: 

  1. 1 <= preorder.length <= 100
  2. The values of preorder are distinct.

根据二叉搜索树的先序遍历结果,构造该二叉搜索树。

简单题。先序遍历是根、左、右,又因为是二叉搜索树,所以左<根<右,所以数组中第一个元素是根节点,然后找到数组右边第一个大于根节点的树,把数组划分为左子树和右子树,然后递归构造。

完整代码如下:

class Solution {
public:
	TreeNode* Work(vector<int> &preorder, int l, int r) {
		if (l > r)return NULL;
		if (l == r)return new TreeNode(preorder[l]);
		TreeNode *root = new TreeNode(preorder[l]);
		int mid = -1;
		for (int i = l; i <= r; ++i) {
			if (preorder[i] > root->val) {
				mid = i;
				break;
			}
		}
		if (mid == -1)root->left = Work(preorder, l + 1, r);
		else {
			root->left = Work(preorder, l + 1, mid - 1);
			root->right = Work(preorder, mid, r);
		}
		return root;
	}
	TreeNode* bstFromPreorder(vector<int>& preorder) {
		return Work(preorder, 0, preorder.size() - 1);
	}
};

本代码提交AC,用时8MS。

LeetCode Minimum Number of Frogs Croaking

1419. Minimum Number of Frogs Croaking

Given the string croakOfFrogs, which represents a combination of the string “croak” from different frogs, that is, multiple frogs can croak at the same time, so multiple “croak” are mixed. Return the minimum number of different frogs to finish all the croak in the given string.

A valid “croak” means a frog is printing 5 letters ‘c’, ’r’, ’o’, ’a’, ’k’ sequentially. The frogs have to print all five letters to finish a croak. If the given string is not a combination of valid “croak” return -1.

Example 1:

Input: croakOfFrogs = "croakcroak"
Output: 1 
Explanation: One frog yelling "croak" twice.

Example 2:

Input: croakOfFrogs = "crcoakroak"
Output: 2 
Explanation: The minimum number of frogs is two. 
The first frog could yell "crcoakroak".
The second frog could yell later "crcoakroak".

Example 3:

Input: croakOfFrogs = "croakcrook"
Output: -1
Explanation: The given string is an invalid combination of "croak" from different frogs.

Example 4:

Input: croakOfFrogs = "croakcroa"
Output: -1

Constraints:

  • 1 <= croakOfFrogs.length <= 10^5
  • All characters in the string are: 'c''r''o''a' or 'k'.

这题有点意思,比赛结束前3分钟我才AC了。。。

给定一个字符串,表示青蛙咳嗽的字符串。青蛙每咳一声,会发出croak这一串字符。现在有多个青蛙同时咳嗽,则多个croak会被打乱输出,可以想象下多线程输出到同一个文件时,顺序是乱的。

问一个咳嗽字符串最少可以由几个青蛙产生的,注意青蛙咳完一声后可以接着咳。

我一开始的做法比较暴力,对于每个字符,检查它是否属于之前某个青蛙的咳嗽字符串中,如果属于则放入,不属于且是c的话,则新开一个咳嗽字符串。完整代码如下:

class Solution {
public:
	int minNumberOfFrogs(string croakOfFrogs) {
		map<char, char> pre = { {'r','c'},{'o','r'},{'a','o'},{'k','a'} };
		vector<vector<char>> ans;
		map<char, int> count;
		for (int i = 0; i < croakOfFrogs.size(); ++i) {
			int letter = croakOfFrogs[i];
			++count[letter];
			if (!(count['c'] >= count['r'] && count['r'] >= count['o'] && count['o'] >= count['a'] && count['a'] >= count['k']))return -1;
			if (letter == 'c') {
				if (ans.empty()) {
					ans.push_back({ 'c' });
				}
				else {
					bool found = false;
					for (int j = 0; j < ans.size(); ++j) {
						if (ans[j].empty()) {
							ans[j].push_back('c');
							found = true;
							break;
						}
					}
					if (!found) {
						ans.push_back({ 'c' });
					}
				}
			}
			else {
				if (ans.empty())return -1;
				else {
					bool found = false;
					for (int j = 0; j < ans.size(); ++j) {
						if (!ans[j].empty() && ans[j].back() == pre[letter]) {
							ans[j].push_back(letter);
							found = true;
							if (letter == 'k')ans[j].clear();
							break;
						}
					}
					if (!found)return -1;
				}
			}
		}

		for (int j = 0; j < ans.size(); ++j) {
			if (!ans[j].empty())return -1;
		}

		return ans.size();
	}
};

这个解法TLE了,最后几个测试用例过不了。这个解法的问题是对每个字符都要遍历之前所有青蛙的咳嗽数组,太耗时了。

后来想到一种O(n)解法。因为咳嗽字符串是croak,在遍历的过程中,只要满足出现次数c>=r>=o>=a>=k就是合法的。然后设定一个free变量,记录当前有多少只青蛙是之前咳嗽结束了,已经空闲下来,可以进行下一轮咳嗽了。如果来一个c,且有free的话,则拿一个free的青蛙进行咳嗽,否则新开一个青蛙。如果新来一个k,则说明这个青蛙咳嗽结束,多一个空闲青蛙,free++。

完整代码如下:

class Solution {
public:
	int minNumberOfFrogs(string croakOfFrogs) {
		int n = croakOfFrogs.size();
		map<char, int> count;
		int free = 0, ans = 0;
		for (int i = 0; i < croakOfFrogs.size(); ++i) {
			char letter = croakOfFrogs[i];
			++count[letter];
			if (!(count['c'] >= count['r'] && count['r'] >= count['o'] && count['o'] >= count['a'] && count['a'] >= count['k']))return -1;
			if (letter == 'c'&&free == 0) {
				++ans;
			}
			else if (letter == 'c'&&free > 0) {
				--free;
			}
			else if (letter == 'k') {
				++free;
			}
		}
		if (count['c'] != count['k'])return -1;
		return ans;
	}
};

本代码提交AC,用时388MS。

LeetCode Display Table of Food Orders in a Restaurant

1418. Display Table of Food Orders in a Restaurant

Given the array orders, which represents the orders that customers have done in a restaurant. More specifically orders[i]=[customerNamei,tableNumberi,foodItemi] where customerNamei is the name of the customer, tableNumberi is the table customer sit at, and foodItemi is the item customer orders.

Return the restaurant’s “display table. The “display table” is a table whose row entries denote how many of each food item each table ordered. The first column is the table number and the remaining columns correspond to each food item in alphabetical order. The first row should be a header whose first column is “Table”, followed by the names of the food items. Note that the customer names are not part of the table. Additionally, the rows should be sorted in numerically increasing order.

Example 1:

Input: orders = [["David","3","Ceviche"],["Corina","10","Beef Burrito"],["David","3","Fried Chicken"],["Carla","5","Water"],["Carla","5","Ceviche"],["Rous","3","Ceviche"]]
Output: [["Table","Beef Burrito","Ceviche","Fried Chicken","Water"],["3","0","2","1","0"],["5","0","1","0","1"],["10","1","0","0","0"]] 
Explanation:
The displaying table looks like:
Table,Beef Burrito,Ceviche,Fried Chicken,Water
3    ,0           ,2      ,1            ,0
5    ,0           ,1      ,0            ,1
10   ,1           ,0      ,0            ,0
For the table 3: David orders "Ceviche" and "Fried Chicken", and Rous orders "Ceviche".
For the table 5: Carla orders "Water" and "Ceviche".
For the table 10: Corina orders "Beef Burrito". 

Example 2:

Input: orders = [["James","12","Fried Chicken"],["Ratesh","12","Fried Chicken"],["Amadeus","12","Fried Chicken"],["Adam","1","Canadian Waffles"],["Brianna","1","Canadian Waffles"]]
Output: [["Table","Canadian Waffles","Fried Chicken"],["1","2","0"],["12","0","3"]] 
Explanation: 
For the table 1: Adam and Brianna order "Canadian Waffles".
For the table 12: James, Ratesh and Amadeus order "Fried Chicken".

Example 3:

Input: orders = [["Laura","2","Bean Burrito"],["Jhon","2","Beef Burrito"],["Melissa","2","Soda"]]
Output: [["Table","Bean Burrito","Beef Burrito","Soda"],["2","1","1","1"]]

Constraints:

  • 1 <= orders.length <= 5 * 10^4
  • orders[i].length == 3
  • 1 <= customerNamei.length, foodItemi.length <= 20
  • customerNamei and foodItemi consist of lowercase and uppercase English letters and the space character.
  • tableNumberi is a valid integer between 1 and 500.

很啰嗦的一个题目。给定一系列顾客的点餐清单,输出整个餐厅的点餐信息表。直接按照题意做就行,题目要求行按桌号升序排列,列按菜名字母序排列,所以行可以用vector下标存储,菜名放到set里会自动有序排列。

完整代码如下:

class Solution {
public:
	vector<vector<string>> displayTable(vector<vector<string>>& orders) {
		vector<map<string, int>> tables(501, map<string, int>());
		set<string> allfoods;
		for (int i = 0; i < orders.size(); ++i) {
			string name = orders[i][0], tb = orders[i][1], food = orders[i][2];
			int ntb = stoi(tb.c_str());
			++tables[ntb][food];
			allfoods.insert(food);
		}
		vector<vector<string>> ans;
		vector<string> header;
		header.push_back("Table");
		for (set<string>::iterator it = allfoods.begin(); it != allfoods.end(); ++it)header.push_back(*it);
		ans.push_back(header);
		for (int i = 1; i <= 500; ++i) {
			vector<string> cur;
			if (tables[i].size() > 0) {
				cur.push_back(to_string(i));
				for (set<string>::iterator it = allfoods.begin(); it != allfoods.end(); ++it) {
					cur.push_back(to_string(tables[i][*it]));
				}
				ans.push_back(cur);
			}
		}
		return ans;
	}
};

本代码提交AC,用时1152MS。

LeetCode Reformat The String

1417. Reformat The String

Given alphanumeric string s. (Alphanumeric string is a string consisting of lowercase English letters and digits).

You have to find a permutation of the string where no letter is followed by another letter and no digit is followed by another digit. That is, no two adjacent characters have the same type.

Return the reformatted string or return an empty string if it is impossible to reformat the string.

Example 1:

Input: s = "a0b1c2"
Output: "0a1b2c"
Explanation: No two adjacent characters have the same type in "0a1b2c". "a0b1c2", "0a1b2c", "0c2a1b" are also valid permutations.

Example 2:

Input: s = "leetcode"
Output: ""
Explanation: "leetcode" has only characters so we cannot separate them by digits.

Example 3:

Input: s = "1229857369"
Output: ""
Explanation: "1229857369" has only digits so we cannot separate them by characters.

Example 4:

Input: s = "covid2019"
Output: "c2o0v1i9d"

Example 5:

Input: s = "ab123"
Output: "1a2b3"

Constraints:

  • 1 <= s.length <= 500
  • s consists of only lowercase English letters and/or digits.

给定一个包含字母和数字的字符串,输出将字母和数字交替排列的字符串,输出任意一个合法的即可。

简单题,首先先统计下字母和数字的个数,要让交替出现,则它们的个数之差必须小于2。然后把个数多的排前面,交替排列即可。完整代码如下:

class Solution {
public:
	string reformat(string s) {
		string alpha = "", digit = "";
		for (int i = 0; i < s.size(); ++i) {
			if (s[i] >= '0'&&s[i] <= '9')digit.push_back(s[i]);
			else alpha.push_back(s[i]);
		}

		int a = alpha.size(), d = digit.size();
		if (abs(a - d) >= 2)return "";
		string ans = "";
		int i = 0, j = 0;
		if (a > d) {
			while (i < a || j < d) {
				ans.push_back(alpha[i++]);
				if (j < d)ans.push_back(digit[j++]);
			}
		}
		else {
			while (i < a || j < d) {
				ans.push_back(digit[j++]);
				if (i < a)ans.push_back(alpha[i++]);
			}
		}
		return ans;
	}
};

本代码提交AC,用时12MS。

LCP 09. 最小跳跃次数

LCP 09. 最小跳跃次数

为了给刷题的同学一些奖励,力扣团队引入了一个弹簧游戏机。游戏机由 N 个特殊弹簧排成一排,编号为 0 到 N-1。初始有一个小球在编号 0 的弹簧处。若小球在编号为 i 的弹簧处,通过按动弹簧,可以选择把小球向右弹射 jump[i] 的距离,或者向左弹射到任意左侧弹簧的位置。也就是说,在编号为 i 弹簧处按动弹簧,小球可以弹向 0 到 i-1 中任意弹簧或者 i+jump[i] 的弹簧(若 i+jump[i]>=N ,则表示小球弹出了机器)。小球位于编号 0 处的弹簧时不能再向左弹。

为了获得奖励,你需要将小球弹出机器。请求出最少需要按动多少次弹簧,可以将小球从编号 0 弹簧弹出整个机器,即向右越过编号 N-1 的弹簧。

示例 1:

输入:jump = [2, 5, 1, 1, 1, 1]

输出:3

解释:小 Z 最少需要按动 3 次弹簧,小球依次到达的顺序为 0 -> 2 -> 1 -> 6,最终小球弹出了机器。

限制:

1 <= jump.length <= 10^6
1 <= jump[i] <= 10000


给定一个数组,每个数表示能从该位置往右跳的的步数。每个位置,要么往右一次性跳这么多步,要么可以跳回左边任意位置。问要跳出最右边,需要最少跳是多少。

每跳到一个i,可以往右跳到i+jump[i],或者跳回[0,i-1]任意位置。采用BFS思路,i+jump[i]和[0,i-1]任意位置作为BFS的一层。但是,简单的BFS会TLE。每轮BFS时,记录[0,i-1]测试过的最大位置,下次只要从这个位置开始测试即可。

完整代码如下:

class Solution {
public:
	int minJump(vector<int>& jump) {
		int n = jump.size();
		vector<int> visited(n, 0);
		visited[0] = 1;
		queue<int> q;
		q.push(0);
		int steps = 0;
		int premax = 0;
		while (!q.empty()) {
			++steps;
			int sz = q.size();
			while (sz--) {
				int cur = q.front();
				q.pop();
				int next = cur + jump[cur];
				if (next >= n)return steps;
				if (visited[next] == 0) {
					q.push(next);
				}
				for (int pre = premax; pre < cur; ++pre) {
					if (visited[pre] == 0) {
						visited[pre] = 1;
						q.push(pre);
					}
				}
				premax = max(premax, cur);
			}
		}
		return 0;
	}
};

本代码提交AC,用时544MS。

LCP 08. 剧情触发时间

LCP 08. 剧情触发时间

在战略游戏中,玩家往往需要发展自己的势力来触发各种新的剧情。一个势力的主要属性有三种,分别是文明等级(C),资源储备(R)以及人口数量(H)。在游戏开始时(第 0 天),三种属性的值均为 0。

随着游戏进程的进行,每一天玩家的三种属性都会对应增加,我们用一个二维数组 increase 来表示每天的增加情况。这个二维数组的每个元素是一个长度为 3 的一维数组,例如 [[1,2,1],[3,4,2]] 表示第一天三种属性分别增加 1,2,1 而第二天分别增加 3,4,2

所有剧情的触发条件也用一个二维数组 requirements 表示。这个二维数组的每个元素是一个长度为 3 的一维数组,对于某个剧情的触发条件 c[i], r[i], h[i],如果当前 C >= c[i] 且 R >= r[i] 且 H >= h[i] ,则剧情会被触发。

根据所给信息,请计算每个剧情的触发时间,并以一个数组返回。如果某个剧情不会被触发,则该剧情对应的触发时间为 -1 。

示例 1:

输入: increase = [[2,8,4],[2,5,0],[10,9,8]] requirements = [[2,11,3],[15,10,7],[9,17,12],[8,1,14]]

输出: [2,-1,3,-1]

解释:

初始时,C = 0,R = 0,H = 0

第 1 天,C = 2,R = 8,H = 4

第 2 天,C = 4,R = 13,H = 4,此时触发剧情 0

第 3 天,C = 14,R = 22,H = 12,此时触发剧情 2

剧情 1 和 3 无法触发。

示例 2:

输入: increase = [[0,4,5],[4,8,8],[8,6,1],[10,10,0]] requirements = [[12,11,16],[20,2,6],[9,2,6],[10,18,3],[8,14,9]]

输出: [-1,4,3,3,3]

示例 3:

输入: increase = [[1,1,1]] requirements = [[0,0,0]]

输出: [0]

限制:

  • 1 <= increase.length <= 10000
  • 1 <= requirements.length <= 100000
  • 0 <= increase[i] <= 10
  • 0 <= requirements[i] <= 100000

玩家有c,r,h三个值,每过一天三个值有不同程度的增加,问满足不同阈值的最小天数。

暴力方法两层循环会超时。可以先分别构建c,r,h的递增数组,然后针对每个requirement,在递增数组中二分查找满足阈值的左边界,三个左边界的最大值即为满足3个条件的最小天数。

完整代码如下:

class Solution {
public:
	vector<int> getTriggerTime(vector<vector<int>>& increase, vector<vector<int>>& requirements) {
		int m = increase.size(), n = requirements.size();
		vector<int> cs(m + 1, 0), rs(m + 1, 0), hs(m + 1, 0);

		for (int i = 0; i < m; ++i) {
			cs[i + 1] = cs[i] + increase[i][0];
			rs[i + 1] = rs[i] + increase[i][1];
			hs[i + 1] = hs[i] + increase[i][2];
		}

		vector<int> ans(n, -1);

		for (int i = 0; i < n; ++i) {
			int minc = lower_bound(cs.begin(), cs.end(), requirements[i][0]) - cs.begin();
			int minr = lower_bound(rs.begin(), rs.end(), requirements[i][1]) - rs.begin();
			int minh = lower_bound(hs.begin(), hs.end(), requirements[i][2]) - hs.begin();
			int cur = max(max(minc, minr), minh);
			if (cur <= m)ans[i] = cur;
		}


		return ans;
	}
};

本代码提交AC,用时988MS。

LCP 07. 传递信息

LCP 07. 传递信息

小朋友 A 在和 ta 的小伙伴们玩传信息游戏,游戏规则如下:

  1. 有 n 名玩家,所有玩家编号分别为 0 ~ n-1,其中小朋友 A 的编号为 0
  2. 每个玩家都有固定的若干个可传信息的其他玩家(也可能没有)。传信息的关系是单向的(比如 A 可以向 B 传信息,但 B 不能向 A 传信息)。
  3. 每轮信息必须需要传递给另一个人,且信息可重复经过同一个人

给定总玩家数 n,以及按 [玩家编号,对应可传递玩家编号] 关系组成的二维数组 relation。返回信息从小 A (编号 0 ) 经过 k 轮传递到编号为 n-1 的小伙伴处的方案数;若不能到达,返回 0。

示例 1:

输入:n = 5, relation = [[0,2],[2,1],[3,4],[2,3],[1,4],[2,0],[0,4]], k = 3

输出:3

解释:信息从小 A 编号 0 处开始,经 3 轮传递,到达编号 4。共有 3 种方案,分别是 0->2->0->4, 0->2->1->4, 0->2->3->4。

示例 2:

输入:n = 3, relation = [[0,2],[2,1]], k = 2

输出:0

解释:信息不能从小 A 处经过 2 轮传递到编号 2

限制:

  • 2 <= n <= 10
  • 1 <= k <= 5
  • 1 <= relation.length <= 90, 且 relation[i].length == 2
  • 0 <= relation[i][0],relation[i][1] < n 且 relation[i][0] != relation[i][1]

给定n名玩家,以及玩家的传递关系。问从0号玩家经过k轮传递到n-1号玩家的方案数。

首先把玩家传递关系建一个图,然后从0号节点开始BFS,并统计传递的步数。当步数为k且到达n-1号玩家时,方案数加一。完整代码如下:

class Solution {
public:
	int numWays(int n, vector<vector<int>>& relation, int k) {
		vector<vector<int>> graph(n, vector<int>(n, 0));
		for (int i = 0; i < relation.size(); ++i) {
			graph[relation[i][0]][relation[i][1]] = 1;
		}
		queue<pair<int, int>> q;
		q.push(make_pair(0, 0));
		int ans = 0;
		while (!q.empty()) {
			pair<int, int> p = q.front();
			q.pop();
			if (p.first == n - 1 && p.second == k)++ans;
			if (p.second < k) {
				for (int i = 0; i < n; ++i) {
					if (graph[p.first][i] == 1) {
						q.push(make_pair(i, p.second + 1));
					}
				}
			}
		}
		return ans;
	}
};

本代码提交AC,用时8MS。

LCP 06. 拿硬币

LCP 06. 拿硬币

桌上有 n 堆力扣币,每堆的数量保存在数组 coins 中。我们每次可以选择任意一堆,拿走其中的一枚或者两枚,求拿完所有力扣币的最少次数。

示例 1:

输入:[4,2,1]

输出:4

解释:第一堆力扣币最少需要拿 2 次,第二堆最少需要拿 1 次,第三堆最少需要拿 1 次,总共 4 次即可拿完。

示例 2:

输入:[2,3,10]

输出:8

限制:

  • 1 <= n <= 4
  • 1 <= coins[i] <= 10

有一个硬币数组,每次可以拿1枚或2枚,问最少拿多少次可以拿完。

简单题,贪心,每次拿2枚。完整代码如下:

class Solution {
public:
	int minCount(vector<int>& coins) {
		int ans = 0;
		for (int i = 0; i < coins.size(); ++i) {
			ans += (coins[i] / 2);
			if (coins[i] % 2 == 1)++ans;
		}
		return ans;
	}
};

本代码提交AC,用时4MS。

LeetCode Valid Parenthesis String

678. Valid Parenthesis String

Given a string containing only three types of characters: ‘(‘, ‘)’ and ‘*’, write a function to check whether this string is valid. We define the validity of a string by these rules:

  1. Any left parenthesis '(' must have a corresponding right parenthesis ')'.
  2. Any right parenthesis ')' must have a corresponding left parenthesis '('.
  3. Left parenthesis '(' must go before the corresponding right parenthesis ')'.
  4. '*' could be treated as a single right parenthesis ')' or a single left parenthesis '(' or an empty string.
  5. An empty string is also valid.

Example 1:

Input: "()"
Output: True

Example 2:

Input: "(*)"
Output: True

Example 3:

Input: "(*))"
Output: True

Note:

  1. The string size will be in the range [1, 100].

给定一个字符串,里面包含左括号、右括号和星号,星号可以表示左括号、右括号或空格。问这个字符串是否可能是一个合法的括号字符串。

这题有点难理解,直接看题解。

解法1,两遍扫描法,好理解。星号有3种情况,第一次假设星号全部是左括号,如果能满足左括号总数≥右括号总数,说明字符串中的右括号不会太多,用星号加原有的左括号能抵消掉所有的右括号。第二次假设星号全部是右括号,如果能满足右括号总数≥左括号总数,说明字符串中的左括号不会太多,用星号加原有的右括号能抵消掉所有的左括号。由于星号还可以表示空格,所以如果上述两种情况都满足,则多于的星号可以换成空格。

该解法本质上考虑了两种极端情况,而合法解肯定在这两个极端之间。

在以上两种情况的判断过程中,扫描的时候如果不满足条件可以提前终止。比如假设星号全部是左括号时,从左往右扫描字符串,如果出现右括号数大于左括号数的情况,直接返回false。因为我已经把所有星号假设为左括号了,但还是满足不了右括号,说明右括号太多了,非法。类似的,当假设星号为右括号时,从右往左扫描,也可以提前终止。完整代码如下:

class Solution {
public:
	bool checkValidString(string s) {
		int left_balance = 0;
		for (int i = 0; i < s.size(); ++i) {
			if (s[i] == '(' || s[i] == '*')++left_balance;
			else --left_balance;
			if (left_balance < 0)return false;
		}
		if (left_balance == 0)return true;

		int right_balance = 0;
		for (int i = s.size() - 1; i >= 0; --i) {
			if (s[i] == ')' || s[i] == '*')++right_balance;
			else --right_balance;
			if (right_balance < 0)return false;
		}
		return true;
	}
};

本代码提交AC,用时0MS。

解法2,一遍扫描法,不太好理解。定义字符串中多余出来的左括号数的最小值min_left和最大值max_left。从左往右扫描字符串,遇到左括号,则min_left和max_left都要加一;遇到右括号,则min_left和max_left都要减一;遇到星号时,把它当做右括号,则min_left减一,把它当做左括号,则max_lfet加一。如果[min_left, max_left]区间包括0,则说明字符串有可能是合法的,因为多余的左括号等于0的话,说明左右括号平衡了。完整代码如下:

class Solution {
public:
	bool checkValidString(string s) {
		int min_left = 0, max_left = 0;
		for (int i = 0; i < s.size(); ++i) {
			min_left += (s[i] == '(' ? 1 : -1);
			max_left += (s[i] != ')' ? 1 : -1);
			if (max_left < 0)break;
			min_left = max(min_left, 0);
		}
		return min_left == 0;
	}
};

本代码提交AC,用时0MS。

LeetCode Perform String Shifts

LeetCode Perform String Shifts

You are given a string s containing lowercase English letters, and a matrix shift, where shift[i] = [direction, amount]:

  • direction can be 0 (for left shift) or 1 (for right shift). 
  • amount is the amount by which string s is to be shifted.
  • A left shift by 1 means remove the first character of s and append it to the end.
  • Similarly, a right shift by 1 means remove the last character of s and add it to the beginning.

Return the final string after all operations.

Example 1:

Input: s = "abc", shift = [[0,1],[1,2]]
Output: "cab"
Explanation: 
[0,1] means shift to left by 1. "abc" -> "bca"
[1,2] means shift to right by 2. "bca" -> "cab"

Example 2:

Input: s = "abcdefg", shift = [[1,1],[1,1],[0,2],[1,3]]
Output: "efgabcd"
Explanation:  
[1,1] means shift to right by 1. "abcdefg" -> "gabcdef"
[1,1] means shift to right by 1. "gabcdef" -> "fgabcde"
[0,2] means shift to left by 2. "fgabcde" -> "abcdefg"
[1,3] means shift to right by 3. "abcdefg" -> "efgabcd"

Constraints:

  • 1 <= s.length <= 100
  • s only contains lower case English letters.
  • 1 <= shift.length <= 100
  • shift[i].length == 2
  • 0 <= shift[i][0] <= 1
  • 0 <= shift[i][1] <= 100

给定一个字符串s,并且给定一些向左或向右shift的操作,问经过这些操作之后,字符串最终的形式是怎样的。

简单题,虽然有很多操作,但可以先把向左的操作数累加,向右的操作数累加,最后比比大小,看最终是向左还是向右。完整代码如下:

class Solution {
public:
	string stringShift(string s, vector<vector<int>>& shift) {
		int left = 0, right = 0, n = s.size();
		for (int i = 0; i < shift.size(); ++i) {
			if (shift[i][0] == 0)left += shift[i][1];
			else right += shift[i][1];
		}
		if (left > right) {
			left -= right;
			left %= n;
			return s.substr(left) + s.substr(0, left);
		}
		else if (right > left) {
			right -= left;
			right %= n;
			return s.substr(n - right) + s.substr(0, n - right);
		}
		else {
			return s;
		}
	}
};

本代码提交AC,用时0MS。