leetcode Weekly Contest 112

前言

leetcode 每周末都会举行编程比赛,一共四道题,虽然都有参加,但是水平依然有限,名词并不是很好。不过参加比赛的一个好处就是可以在比赛后review别人的解答,这是一个非常棒的学习材料,因为可以从别人的解答里发现高手的脑回路。因此这里挑选别人的解题代码进行讲解、归纳而不是我自己的答案,希望这归纳也能给大家带来启发!

leetcode 945. Minimum Increment to Make Array Unique

题目

Given an array of integers A, a move consists of choosing any A[i], and incrementing it by 1.

Return the least number of moves to make every value in A unique.

Example 1:

Input: [1,2,2]
Output: 1
Explanation:  After 1 move, the array could be [1, 2, 3].
Example 2:

Input: [3,2,1,2,1,7]
Output: 6
Explanation:  After 6 moves, the array could be [3, 4, 1, 2, 5, 7].
It can be shown with 5 or less moves that it is impossible for the array to have all unique values.

Note:
0 <= A.length <= 40000
0 <= A[i] < 40000

思路

给出A数组中的数字并不是唯一的,每次对这些数字只能加一,统计最小的加一的次数。可以使用贪心算法进行求解,对A数组进行从小到大的排序使得A[i+1]>=A[i],遇到重复的数字(A[i+1] == A[i])之后,便在当前的数字基础上加一(A[i+1]++),即,使得A[i+1] = A[i] + 1即可,刚刚好满足题目最小的要求。以此类推再遍历数组A一遍即可。

他山之石,可以攻玉

// using c++
//Ref:@neal_wu
class Solution {
public:
    int minIncrementForUnique(vector<int>& A) {
        sort(A.begin(), A.end());
        int lowest = -1, total = 0;

        for (int a : A) {
            lowest = max(lowest, a);
            total += lowest - a;
            lowest++;
        }

        return total;
    }
};

Note:使用c++进行遍历的时候,c++11的新特性可以使遍历的代码更加简单

leetcode 946. Validate Stack Sequences

题目

Given two sequences pushed and popped with distinct values, return true if and only if this could have been the result of a sequence of push and pop operations on an initially empty stack.

 

Example 1:

Input: pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
Output: true
Explanation: We might do the following sequence:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
Example 2:

Input: pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
Output: false
Explanation: 1 cannot be popped before 2.

Note:
0 <= pushed.length == popped.length <= 1000
0 <= pushed[i], popped[i] < 1000
pushed is a permutation of popped.
pushed and popped have distinct values.

思路

题目要求模拟一个栈的运行,最简单的方法就是使用库中的stack进行模拟运行来判断,因此只要定义好出错条件即可。

  • 每压入一个pushed元素,将当前栈顶元素与puped数组元素比较
  • 如果相等,弹出栈顶元素
  • 继续遍历、压入pushed元素
  • 如果遍历结束pushed元素,pushed和poped数组都为空,则表示符合栈的要求。其他情况均返回false。

他山之石,可以攻玉

// using c++
//Ref:@user0947c
class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        stack < int > s;
        int j = 0;
        for (int i = 0; i < pushed.size(); i++) {
            s.push(pushed[i]);
            while (!s.empty() && j < popped.size() && s.top() == popped[j]) {
                s.pop();
                j++;
            }
        }
        
        return s.empty() && j == popped.size();
    }
};

leetcode 947. Most Stones Removed with Same Row or Column

题目

On a 2D plane, we place stones at some integer coordinate points.  Each coordinate point may have at most one stone.

Now, a move consists of removing a stone that shares a column or row with another stone on the grid.

What is the largest possible number of moves we can make?

 

Example 1:

Input: stones = [[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]]
Output: 5
Example 2:

Input: stones = [[0,0],[0,2],[1,1],[2,0],[2,2]]
Output: 3
Example 3:

Input: stones = [[0,0]]
Output: 0

Note:
1 <= stones.length <= 1000
0 <= stones[i][j] < 10000.

思路

判断这种不相交集合的问题,使用并查集是最方便的解决方法(并查集的基本概念在其他题目中也有使用:LeetCode 721. Accounts Merge)。
这里不同的一点是操作对象变成了平面中的点,相当于增加了维数,因此在初始化并查集数组的时候,注意使用总共(x+y)大小进行初始化即可。

他山之石,可以攻玉

// using c++
//Ref:@awic
class DSU
{
private:
    vector<int> parent;
public:
    DSU(int n) {
        parent.resize(n);
        for(int i = 0; i<n; ++i)
            parent[i] = i;
    };
    ~DSU() = default;
    
    int find(int x) {
        if(parent[x] != x)
            parent[x] = find(parent[x]);
        return parent[x];
    }
    void union_(int x, int y) {
        parent[find(x)] = find(y);
    }
};

class Solution {
public:
    int removeStones(vector<vector<int>>& stones)
    {
        int n = stones.size();
        DSU dsu(20000);

        for (const auto& stone : stones) {
            dsu.union_(stone[0], stone[1]+10000);
        }
        set<int> seen;
        for (const auto& stone : stones) {
            seen.insert(dsu.find(stone[0]));
        }
        return n-seen.size();
    }
};

948. Bag of Tokens

题目

You have an initial power P, an initial score of 0 points, and a bag of tokens.

Each token can be used at most once, has a value token[i], and has potentially two ways to use it.

If we have at least token[i] power, we may play the token face up, losing token[i] power, and gaining 1 point.
If we have at least 1 point, we may play the token face down, gaining token[i] power, and losing 1 point.
Return the largest number of points we can have after playing any number of tokens.

 

Example 1:

Input: tokens = [100], P = 50
Output: 0
Example 2:

Input: tokens = [100,200], P = 150
Output: 1
Example 3:

Input: tokens = [100,200,300,400], P = 200
Output: 2

tokens.length <= 1000
0 <= tokens[i] < 10000
0 <= P < 10000

思路

当时做的时候没有看懂题,纠结了很久,其实题意和解题思路都很简单,和第一题一样使用贪心算法即可。
题目要求返回最多能得到多少分,换言之就是在给定初始能量P的情况下尽可能多翻正面的牌子。

  1. 按照牌子的能量从小到大进行排序
  2. 先翻能量小的牌子到正面,翻到翻不动为止,记录当前得分。
  3. 然后用1个积分翻最大的能量牌子。
  4. 继续第2, 3个步骤,直到遍历完所有元素或者翻不动正面的牌子且没有足够积分换能量,退出。

注意:因为题解同时从数组的头和尾进行遍历,遍历时相遇的情况一定要仔细判断。

他山之石,可以攻玉

// using c++
//Ref:@user0947c  
class Solution {
public:
    int bagOfTokensScore(vector<int>& tokens, int P) {
        sort(tokens.begin(), tokens.end());
        int i = 0, j = tokens.size()-1;
        int cur = 0, maxx = 0;
        while (i <= j) {
            if (tokens[i] <= P) {
                cur++;
                maxx = max(maxx, cur);
                P -= tokens[i];
                i++;
            }
            else if (cur > 0) {
                P += tokens[j];
                cur--;
                j--;
            }
            else break;
        }
        return maxx;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值