Sword Finger Offer (C++)-JZ61: Poker Straight (Algorithm-Simulation)

Author: Zhai Tianbao Steven
Copyright Statement: The copyright belongs to the author. For commercial reprinting, please contact the author for authorization. For non-commercial reprinting, please indicate the source.

Topic description:

Now there are 2 decks of playing cards, and five playing cards are randomly selected from the playing cards. We need to judge whether they are straight or not.
There are the following rules:
1. A is 1, J is 11, Q is 12, K is 13, A cannot be regarded as 14 2.
Big and small kings are 0, 0 can be regarded as any card
3. If five cards are given If the cards can form a straight (that is, these five cards are consecutive), it will output true, otherwise it will output false.
4. The data ensures that each group has 5 numbers, each group contains up to 4 zeros, and the value of the array is [0, 13]

Requirements: Space complexity O(1), time complexity O(nlogn), this problem also has a solution with time complexity O(n)

Example:

enter:

[6,0,2,0,4]

return value:

true

illustrate:

The two 0s in the middle are regarded as 3 and 5. That is: [6,3,2,5,4] 
In this way, these five cards are continuous in the interval [2,6], and the output is true

Problem-solving ideas:

This question examines algorithmic scenario simulation. Two ways to solve the problem.

1) Sorting method

       Sort the cards, the complexity is O(nlogn), traverse once O(n), record the number of 0s, interrupt and return false if duplicate data appears, and accumulate non-zero non-duplicate data at intervals. If the final number of 0s is greater than or equal to the interval accumulation number, it means that a straight can be formed.

       For example, 2 0 4 0 0 7, after sorting, 0 0 0 2 4 7, 2 and 4 are separated by 1, 4 and 7 are separated by 2, the three 0s just make up, and the extra 0s can be made up before and after.

      If the number of 0s is the same as the input number, a straight cannot be formed.

      The total complexity is O(nlogn+n), that is, O(nlogn).

2) Search method

       Perform a double cycle. If 0 is found, skip it; use the set's count function to detect whether there are duplicates, and return false if there are duplicates; if there is no problem, insert the value and refresh the maximum value at the same time.

       If it can continue until the end of the cycle, and the difference between the maximum value minus the minimum value is less than 5, it will definitely form a straight, but not vice versa.

       The time complexity is O(n2), the traversal is n, and the search is n, that is, n*n.

3) Advanced search method

       The process is basically the same as the search method, the difference lies in the detection of duplicate values. Because the cards only have 15 numbers at most, 0-14, we make full use of the bit operation characteristics. If we encounter a certain value, such as 5, we set the fifth digit of bm to 1, that is, 0001 0000. Each time we encounter a Refresh bm with new value.

       In this way, the & operation can be used to detect duplicates. Only when a certain bit is 1 will the duplicate flag be triggered and false will be returned. Use the | operation to refresh bm.

       The time complexity is O(n), the traversal is n, and the search is 1, that is, n*1.

Test code:

1) Sorting method

class Solution {
public:
    // 是否顺子
    bool IsContinuous(vector<int>& numbers) {
        // 排序法
        // 时间复杂度O(nlogn+n)=O(nlogn)
        // 快速排序
        sort(numbers.begin(), numbers.end());
        int size = int(numbers.size());
        int zeroNum = 0;
        int diff = 0;
        for(int i = 0; i < size; ++i){
            // 记录0的数量
            if(numbers[i] == 0){
                zeroNum++;
            } 
            // 判断是否有重复数据
            else if(i > 0 && numbers[i - 1] == numbers[i]){
                return false;
            }
            // 累加间隔长度,注意0不参与间隔计算
            else if(i > 0 && numbers[i - 1] != 0){
                // 比如2和3之间无多余间隔,则diff累加0;2和4之间有3这一个间隔,diff累加1
                diff += numbers[i] - numbers[i - 1] - 1;
            }
        }
        // 0的数量只有大于等于多余的间隔长度,才能凑成顺子
        if(zeroNum == size){
            return false;
        }
        else if(zeroNum >= diff){
            return true;
        }
        else{
            return false;
        }
    }
};

2) Search method

class Solution {
public:
    // 是否顺子
    bool IsContinuous(vector<int>& numbers) {
        // 查找法
        // 时间复杂度O(n2)
        int size = int(numbers.size());
        set<int> s;
        int minNum = 13;
        int maxNum = 0;
        for(int i = 0; i < size; ++i){
            // 跳过0
            if(numbers[i] == 0){
                continue;
            } 
            // 检查重复值,复杂度O(n)
            if(s.count(numbers[i])){
                return false;
            }
            // 插入
            s.insert(numbers[i]);
            // 刷新最值
            minNum = min(minNum, numbers[i]);
            maxNum = max(maxNum, numbers[i]);
        }
        // 最大值和最小值之差小于5,则一定能构成顺子
        bool result = (maxNum - minNum) < 5;
        return result;
    }
};

3) Advanced search method

class Solution {
public:
    // 是否顺子
    bool IsContinuous(vector<int>& numbers) {
        // 查找法进阶
        // 时间复杂度O(n)
        int size = int(numbers.size());
        int bm = 0;
        int minNum = 13;
        int maxNum = 0;
        for(int i = 0; i < size; ++i){
            // 跳过0
            if(numbers[i] == 0){
                continue;
            } 
            // 检查重复值,复杂度O(1)
            if((bm & (1 << numbers[i])) != 0){
                return false;
            }
            // 数字对应位改为1
            bm |= (1 << numbers[i]);
            // 刷新最值
            minNum = min(minNum, numbers[i]);
            maxNum = max(maxNum, numbers[i]); 
        }
        // 最大值和最小值之差小于5,则一定能构成顺子
        bool result = (maxNum - minNum) < 5;
        return result;
    }
};

Guess you like

Origin blog.csdn.net/zhaitianbao/article/details/132694103