Leetcode进阶之路——Weekly Contest 137

37 篇文章 0 订阅

感觉这周的题在时间空间没有太卡,每道题用暴力求解都可以过…
1046. Last Stone Weight

We have a collection of rocks, each rock has a positive integer weight.
Each turn, we choose the two heaviest rocks and smash them together. Suppose the stones have weights x and y with x <= y. The result of this smash is:
If x == y, both stones are totally destroyed;
If x != y, the stone of weight x is totally destroyed, and the stone of weight y has new weight y-x.
At the end, there is at most 1 stone left. Return the weight of this stone (or 0 if there are no stones left.)
Example 1:
Input: [2,7,4,1,8,1]
Output: 1
Explanation:
We combine 7 and 8 to get 1 so the array converts to [2,4,1,1,1] then,
we combine 2 and 4 to get 2 so the array converts to [2,1,1,1] then,
we combine 2 and 1 to get 1 so the array converts to [1,1,1] then,
we combine 1 and 1 to get 0 so the array converts to [1] then that’s the value of last stone.

给定一个数组,每次挑选其中最大的两个数,若两数相同,则在原数组中添加0,否则添加两数之差(绝对值)
返回最后得到的数字
直接暴力遍历即可:

class Solution {
public:
    int lastStoneWeight(vector<int>& stones) {
        if(stones.size() < 2) return stones[0];
		priority_queue<int, vector<int>, less<int>> pq;
		for (int s : stones)
			pq.emplace(s);
		while (pq.size() > 2)
		{
			int a = pq.top();
			pq.pop();
			int b = pq.top();
			pq.pop();
			pq.emplace(a - b);
		}
		int a = pq.top();
		pq.pop();
		int b = pq.top();
		return a - b;
	}
};

1047. Remove All Adjacent Duplicates In String

Given a string S of lowercase letters, a duplicate removal consists of choosing two adjacent and equal letters, and removing them.
We repeatedly make duplicate removals on S until we no longer can.
Return the final string after all such duplicate removals have been made. It is guaranteed the answer is unique.
Example 1:
Input: “abbaca”
Output: “ca”
Explanation:
For example, in “abbaca” we could remove “bb” since the letters are adjacent and equal, and this is the only possible move. The result of this move is that the string is “aaca”, of which only “aa” is possible, so the final string is “ca”.

给定一个字符串,若该字符串相邻两个字符相等,则将其删除,直至遍历一遍无操作,返回最后得到的字符串
同样可以暴力遍历

class Solution {
public:
    string removeDuplicates(string S) {
		bool flag = true;
		while (flag)
		{
			flag = false;;
			string s = "";
			for (int i = 1; i < S.length(); ++i)
			{
				if (S[i - 1] == S[i])
				{
					S = S.substr(0, i - 1) + S.substr(i + 1);
					flag = true;
					break;
				}
			}
		}
		return S;
	}
};

但是这样太耗时,换一种类似匹配括号的“队列版”:

class Solution {
public:
    string removeDuplicates(string S) {
		string res = "";
		for (char c : S)
		{
			if (res == "" || res.back() != c)
				res += c;
			else
				res.pop_back();
		}
		return res;
	}
};

1048. Longest String Chain

Given a list of words, each word consists of English lowercase letters.
Let’s say word1 is a predecessor of word2 if and only if we can add exactly one letter anywhere in word1 to make it equal to word2. For example, “abc” is a predecessor of “abac”.
A word chain is a sequence of words [word_1, word_2, …, word_k] with k >= 1, where word_1 is a predecessor of word_2, word_2 is a predecessor of word_3, and so on.
Return the longest possible length of a word chain with words chosen from the given list of words.
Example 1:
Input: [“a”,“b”,“ba”,“bca”,“bda”,“bdca”]
Output: 4
Explanation: one of the longest word chain is “a”,“ba”,“bda”,“bdca”.

给定一个字符串数组,若其中一个字符串word2可以通过另一个字符串word1增加一个字符得到,则他们可以组成一个 word chain
求出最长的word chain
要注意最后的字符串数组顺序可以变,不一定要按原始数组排列,因此我这里先按照长度从小到大重排,后二次遍历求解,只针对长度相差1的判断是否可以组成chain:

class Solution {
public:
    int longestStrChain(vector<string>& words) {
		sort(words.begin(), words.end(), longestStrChainCmp);
		vector<int> dp(words.size(), 0);
		int maxn = 0;
		for (int i = 0; i < words.size(); ++i)
		{
			int cnt = 1;
			for (int j = i - 1; j >= 0; --j)
			{
				if (words[i].length() - words[j].length() > 1) break;
				if (words[i].length() - words[j].length() == 1)
				{
					if (longestStrChainHelper(words[j], words[i]))
						cnt = max(cnt, dp[j] + 1);
				}
			}
			dp[i] = cnt;
			maxn = max(maxn, cnt);
		}
		return maxn;
	}

	// 排序规则
	static bool longestStrChainCmp(const string& s1, const string& s2)
	{
		if (s1.length() < s2.length()) return true;
		if (s1.length() > s2.length()) return false;
		return s1 < s2;
	}
	
	// 判断是否可以组成chain
	bool longestStrChainHelper(string s1, string s2)
	{
		sort(s1.begin(), s1.end());
		sort(s2.begin(), s2.end());
		if (s2.substr(1) == s1 || s2.substr(0, s1.length()) == s1) return true;
		
		for (int i = 0; i < s1.length(); ++i)
		{
			if (s1[i] != s2[i])
			{
				if (s1.substr(i) == s2.substr(i + 1)) return true;
				else return false;
			}
		}
		return false;
	}
};

1049. Last Stone Weight II

We have a collection of rocks, each rock has a positive integer weight.
Each turn, we choose any two rocks and smash them together. Suppose the stones have weights x and y with x <= y. The result of this smash is:
If x == y, both stones are totally destroyed;
If x != y, the stone of weight x is totally destroyed, and the stone of weight y has new weight y-x.
At the end, there is at most 1 stone left. Return the smallest possible weight of this stone (the weight is 0 if there are no stones left.)
Example 1:
Input: [2,7,4,1,8,1]
Output: 1
Explanation:
We can combine 2 and 4 to get 2 so the array converts to [2,7,1,8,1] then,
we can combine 7 and 8 to get 1 so the array converts to [2,1,1,1] then,
we can combine 2 and 1 to get 1 so the array converts to [1,1,1] then,
we can combine 1 and 1 to get 0 so the array converts to [1] then that’s the optimal value.

跟题一差不多,唯一的不同是每次取出的两个数不是最大的,而是任意,只要保证最后得到的数字最小即可
于是再次取出暴力求解,把所有的可能性都保存到集合中,最后遍历集合求绝对值最小的即可:

class Solution {
public:
    int lastStoneWeightII(vector<int>& stones) {
		set<int> stset;
		stset.emplace(0);
		for (int s : stones)
		{
			set<int> tmp;
			for (int t : stset)
			{
				tmp.emplace(t - s);
				tmp.emplace(t + s);
			}
			stset = tmp;
		}
		int res = 1e9;
		for (int t : stset)
		{
			res = min(res, abs(t));
		}
		return res;
	}
};

总感觉这道题是不是有什么公式推导或者证明,有更简单明了的方法?求解~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值