【leetcode_week137】最后一块石头的重量_最长字符串链等

没啥长进,只AC了前两道签到题,还做的非常慢,中间还出错了很多次。



leetcode第137场周赛赛题地址: https://leetcode-cn.com/contest/weekly-contest-137


最后一块石头的重量

有一堆石头,每块石头的重量都是正整数。

每一回合,从中选出两块最重的石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

如果 x == y,那么两块石头都会被完全粉碎; 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为
y-x。 最后,最多只会剩下一块石头。返回此石头的重量。如果没有石头剩下,就返回 0。

提示:

1 <= stones.length <= 30
1 <= stones[i] <= 1000

思路和参赛代码

这题没有想到什么捷径,于是就很简单地按照步骤一步步做,排序后每次取两块最重的进行操作,看最后剩下的石头重量。代码如下:

class Solution {
public:
    bool cmp(const int& l, const int& r){
        return l > r;
    }

    int lastStoneWeight(vector<int>& stones) {
        vector<int>::iterator it1 = stones.begin();
        vector<int>::iterator it2 = stones.begin()+1;
        int ans = 0;
       
        while (!stones.empty()) {
            sort(stones.begin(), stones.end(), greater<int>());
            
            if (stones.size() == 1) {
                ans = stones[0];
                break;
            }
            else if (stones.size() == 0) {
                ans = 0;
                break;
            }
            else {
                vector<int>::iterator it1 = stones.begin();
                
                if (stones[0] == stones[1]) {
                    stones.erase(it1);
                    vector<int>::iterator it2 = stones.begin();
                    stones.erase(it2);
                }
                else {
                    stones[0] -= stones[1];
                    vector<int>::iterator it2 = ++it1;
                    stones.erase(it2);
                }
            }
        }
        return ans;
    }
};

别人的解答

我每次参加周赛感觉都太急,代码很繁很难看。依旧还是需要向大神学习。

class Solution {
public:
    priority_queue<int> H;
    int lastStoneWeight(vector<int>& stones) {
        int n=stones.size(),i,j;
        for(i=0;i<n;i++)H.push(stones[i]);
        while(!H.empty())
        {
            i=H.top();
            H.pop();
            if(H.empty())return i;
            j=H.top();
            H.pop();
            i-=j;
            if(i)H.push(i);
        }
        return 0;
    }
};

还有priority_queue这种方便的东西,我还傻傻地每次都排序。


删除字符串中的所有相邻重复项

给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。

在 S 上反复执行重复项删除操作,直到无法继续删除。

在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。

示例:
输入:“abbaca”
输出:“ca”
解释: 例如,在 “abbaca” 中,我们可以删除 “bb”,由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 "aa"可以执行重复项删除操作,所以最后的字符串为 “ca”。

思路和参赛代码

这题也是想的很简单,直接遍历,碰到两个一样的,就向两边扩散,把前后一样的也一并去除。

class Solution {
public:
    string removeDuplicates(string S) {
        for (int i = 0; !S.empty() && i < S.length()-1; ) {
            if (S[i] == S[i+1]) {
                
                int j = 1;
                while (i-j >= 0 && i+1+j < S.length() && S[i-j] == S[i+j+1]) {
                    j++;
                }
                i = i-j+1;
                S.erase(i, j*2);
            }
            else {
                i++;
            }
        }
        return S;
    }
};

别人的解答

赛后也和同学讨论过这道题,说是可以直接用栈,一想确实很有道理,比我的时间复杂度还要低一些,少了一些比较次数。我看别人的解答也是这个思路,不过没用栈,直接新开了一个string

class Solution {
public:
    string removeDuplicates(string S) {
        string ans;
        int n=S.size(),i;
        for(i=0;i<n;i++)if(ans.empty()||ans.back()!=S[i])ans+=S[i];
        else ans.pop_back();
        return ans;
    }
};

最长字符串链

给出一个单词列表,其中每个单词都由小写英文字母组成。

如果我们可以在 word1 的任何地方添加一个字母使其变成 word2,那么我们认为 word1 是 word2 的前身。例如,"abc"是 “abac” 的前身。
词链是单词 [word_1, word_2, …, word_k] 组成的序列,k >= 1,其中 word_1 是 word_2的前身,word_2 是 word_3 的前身,依此类推。

从给定单词列表 words 中选择单词组成词链,返回词链的最长可能长度。

示例:
输入:[“a”,“b”,“ba”,“bca”,“bda”,“bdca”]
输出:4
解释:最长单词链之一为"a",“ba”,“bda”,“bdca”。

提示:
1 <= words.length <= 1000
1 <= words[i].length <= 16 words[i]
仅由小写英文字母组成。

思路

比赛的时候倒是有想过根据每个字符串的长度,一步步动态规划来慢慢找到最长字符串链,但是,没有做出来。

补一个看了同学的java代码之后写的c++:【但是,超时了,尴尬。。。下次再改改】

class Solution {
public:
    static bool cmp(string &a, string &b) {
        return a.length() < b.length();
    }
    
    static bool IsChild(string tail, string i) {
        int lent = tail.length();
        int leni = i.length();
        
        if (lent != leni-1) {
            return false;
        }
        
        int ii = 0, jj = 0;
        
        for (; ii < leni && jj < lent; ) {
            if (tail[jj] != i[ii]) {
                ii++;
                
            }
            else{
                ii++;
                jj++;
            }
        }
        if (jj == lent) {
            return true;
        }
        else {
            return false;
        }
    }
    
    int longestStrChain(vector<string>& words) {
        sort(words.begin(), words.end(), cmp);
        int len = words.size();
        
        int dp[1000];
        memset(dp, -1, sizeof(dp));
        
        for (int i = 0; i < len; i++) {
            int tail = i-1;
            int max = -1;
            
            while(tail >= 0) {
                if (IsChild(words[tail], words[i])) {
                    if (dp[tail] > max) {
                        max = dp[tail];
                    }
                }
                tail--;
            }
            dp[i] = (max==-1)?1:max+1;
        }
        sort(dp, dp+len);
        return dp[len-1];
    }
};

别人的解答

看到有别人的解答 http://www.cnblogs.com/owenandhisfriends/p/10890627.html 是转化成图来做的,思路感觉挺不错。


最后一块石头的重量 II

有一堆石头,每块石头的重量都是正整数。

每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:

  • 如果 x == y,那么两块石头都会被完全粉碎;
  • 如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头新重量为y-x。 最后,最多只会剩下一块石头。返回此石头最小的可能重量。如果没有石头剩下,就返回 0。

示例:

输入:[2,7,4,1,8,1]
输出:1
解释: 组合 2 和 4,得到 2,所以数组转化为 [2,7,1,8,1], 组合 7 和8,得到 1,所以数组转化为 [2,1,1,1], 组合 2 和 1,得到 1,所以数组转化为 [1,1,1], 组合 1 和 1,得到0,所以数组转化为 [1],这就是最优值。

提示:
1 <= stones.length <= 30
1 <= stones[i] <= 1000

思路

  • 原来是想贪心,先把差值最大的给减出来,然后再找差值最大的,后来发现并不对。
  • 也曾想过把问题转换为添加“+”和“-”来求取最小值的动态规划问题,但是,最终绕晕了,感觉好像也不好做。

没有做出来。

别人的解答

在加入第n个石头重量为m时,查找n-1个石头能够组成的两堆石头的差值的绝对值为diff。

该石头两个选择,放入多的堆,则差值更大,为diff+m;
放入小的堆,则差值为|diff-m|。这时更新n个石头能组成的所有重量。

最后输出最后一个石头能组成的最小重量即可。

详情可见 http://www.cnblogs.com/owenandhisfriends/p/10890627.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值