Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[LeetCode] 846. Hand of Straights #846

Open
grandyang opened this issue May 30, 2019 · 0 comments
Open

[LeetCode] 846. Hand of Straights #846

grandyang opened this issue May 30, 2019 · 0 comments

Comments

@grandyang
Copy link
Owner

grandyang commented May 30, 2019

 

Alice has a hand of cards, given as an array of integers.

Now she wants to rearrange the cards into groups so that each group is size W, and consists of W consecutive cards.

Return true if and only if she can.

 

Example 1:

Input: hand = [1,2,3,6,2,3,4,7,8], W = 3
Output: true
Explanation: Alice's hand can be rearranged as [1,2,3],[2,3,4],[6,7,8]

Example 2:

Input: hand = [1,2,3,4,5], W = 4
Output: false
Explanation: Alice's hand can't be rearranged into groups of 4 

Note:

  1. 1 <= hand.length <= 10000
  2. 0 <= hand[i] <= 10^9
  3. 1 <= W <= hand.length

 

这道题说是我们在打扑克牌,是否能将手里的牌都以顺子的形式出完。在打拐3挖坑或者斗地主的时候,顺子牌在后期的威力是蛮大的,某些人手里憋了一把牌,结果到后期找个机会上手了之后,直接一把甩完,看的手中只有一把单牌的博主是目瞪口呆。其实到了后期,大家手中都没啥牌了的时候,就算是很小的连牌,也不一定能要得起,而划单是最没前途的出法,所以要尽量将手中的牌都组成顺子丢出去。这里给了一个W,规定了顺子的最小长度,那么我们就拿例子1来模拟下打牌吧,首先摸到了牌之后,肯定要先整牌,按从小到大的顺序排列,这里就不考虑啥3最大,4最小啥的,就统一按原始数字排列吧:

1 2 2 3 3 4 6 7 8

好,下面要来组顺子,既然这里是3张可连,那么从最小的开始连呗。其实这道题还是简化了许多,真正打牌的时候,即便是3张起连,那么连4张5张都是可以的,可以这里限定了只能连W张,就使得题目变简单了。我们用贪婪算法就可以了,首先从1开始,那么一定得有2和3,才能起连,若少了任何一个,都可以直接返回false,好那么取出这三张后,手里还有:

2 3 4 6 7 8

那么从当前手里的最小的牌2开始起连,那么手里必须要有3和4,若少了任何一个,都可以直接返回 false,好那么取出这三张后,手里还有:

6 7 8

从当前手里的最小的牌6开始起连,那么手里必须要有7和8,若少了任何一个,都可以直接返回 false,好那么取出这三张后,手里没牌了,我们成功的连完了所有的牌。分析这个过程,不难发现,由于牌可以重复,所以要统计每张牌出现的次数,同时还要给牌按大小排序,用 TreeMap 来建立牌的大小和其出现次数之间的映射就最好不过了,利用了其可以按 key 值排序的特点。首先遍历手中牌,建立映射。然后开始 while 循环,条件是 TreeMap 不为空,然后去除最小的那张牌,然后遍历能组成顺子的W张牌,若没有直接返回 true,有的话,则映射值自减1,若映射值为0了,则从 TreeMap 中移除该映射对儿即可,while 循环退出后返回 true,参见代码如下:

 

解法一:

class Solution {
public:
    bool isNStraightHand(vector<int>& hand, int W) {
        map<int, int> m;
        for (int i : hand) ++m[i];
        while (!m.empty()) {
            int start = m.begin()->first;
            for (int i = 0; i < W; ++i) {
                if (!m.count(start + i)) return false;
                if (--m[start + i] == 0) m.erase(start + i);
            }
        }
        return true;
    }
};

 

我们也可以不对 TreeMap 进行删除操作,而是直接修改其映射值,在建立好映射对儿之后,不用 while 循环,而是遍历所有的映射对儿,若某个映射值为0了,直接跳过。然后还是遍历能组成顺子的W张牌,若某张牌出现的次数小于顺子起始位置的牌的个数,则直接返回 false,因为肯定会有起始牌剩余,无法全组成顺子,这样还避免了上面解法中一张一张减的操作,提高了运算效率。然后映射值减去起始牌的个数,最后 for 循环退出后,返回 true,参见代码如下:

 

解法二:

class Solution {
public:
    bool isNStraightHand(vector<int>& hand, int W) {
        map<int, int> m;
        for (int i : hand) ++m[i];
        for (auto a : m) {
            if (a.second == 0) continue;
            for (int i = a.first; i < a.first + W; ++i) {
                if (m[i] < a.second) return false;
                m[i] = m[i] - a.second;
            }
        }
        return true;
    }
};

 

Github 同步地址:

#846

 

参考资料:

https://leetcode.com/problems/hand-of-straights/

https://leetcode.com/problems/hand-of-straights/discuss/135700/Short-Java-solution!

https://leetcode.com/problems/hand-of-straights/discuss/135598/C%2B%2BJavaPython-O(MlogM)-Complexity

 

LeetCode All in One 题目讲解汇总(持续更新中...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant