BullsAndCows

Author Avatar
Tianqi Zhang 11月 08, 2019

Problem

你正在和你的朋友玩 猜数字(Bulls and Cows)游戏:你写下一个数字让你的朋友猜。每次他猜测后,你给他一个提示,告诉他有多少位数字和确切位置都猜对了(称为“Bulls”, 公牛),有多少位数字猜对了但是位置不对(称为“Cows”, 奶牛)。你的朋友将会根据提示继续猜,直到猜出秘密数字。

请写出一个根据秘密数字和朋友的猜测数返回提示的函数,用 A 表示公牛,用 B 表示奶牛。

请注意秘密数字和朋友的猜测数都可能含有重复数字。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/bulls-and-cows
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

Example 1
输入: secret = "1807", guess = "7810"

输出: "1A3B"

解释: 1 公牛和 3 奶牛。公牛是 8,奶牛是 0, 1 和 7。

Example 2
输入: secret = "1123", guess = "0111"

输出: "1A1B"

解释: 朋友猜测数中的第一个 1 是公牛,第二个或第三个 1 可被视为奶牛。

说明: 你可以假设秘密数字和朋友的猜测数都只包含数字,并且它们的长度永远相等。

Solution-1 直接按照描述求解

这种做法同样可以适用于两个string长度不同len(guess) > len(secret)的情况

class Solution {
public:
    string getHint(string secret, string guess) {
        int bulls{0}, cows{0};
        map<char, int> chars;
        for (char c : secret) {
            if (chars.find(c) == chars.end()) chars[c] = 1;
            else chars[c] += 1;
        }

        for (size_t i = 0; i < secret.size(); ++i) {
            if (guess[i] == secret[i] && chars[guess[i]] > 0) {
                chars[guess[i]] -= 1;
                bulls += 1;
                guess[i] = 'e';
            }
        }

        for (size_t i = 0; i < guess.size(); ++i) {
            if (chars.find(guess[i]) != chars.end() && chars[guess[i]] > 0) {
                chars[guess[i]] -= 1;
                cows += 1;
            }
        }

        ostringstream strio;
        strio << bulls << "A" << cows << "B";

        return strio.str();
    }
};

Solution-2 优化的方法

这种方法只适用于两个字符串长度一样的情况:len(secret) == len(guess) == len,因为字符只有0-9十个,所以可以直接使用数组记录,bulls同样可以直接统计。而对于cows我们只考虑没有归入bulls中的元素,在bucks中记录的元素是num_elem_in_secret - num_elem_in_guess, 我们应该有关系:sum(bucks) == 0,或者假设bucks是两个向量xy之差,其中x[i]=#i in secret, y[i]=#i in guess. 那么应该有sum(x)=sum(y)=len-bulls,那么在这两个向量相减的过程中,相互抵消掉的部分就是同时存在于secretguess的部分,多出来的正值的部分就是只存在于secret中的部分,多出来的负值的部分就是只存在于guess中的部分,那么我们只需要使用len-bulls-sum([i for i in bucks if i > 0])就是同时存在于guesscows中并且不在bulls中的元素个数,即cows.

// Version 1
class Solution {
public:
    string getHint(string secret, string guess) {
        int bulls{0}, cows{0};
        array<int, 10> bucks;
        bucks.fill(0);

        for (size_t i = 0; i < secret.size(); ++i) {
            if (guess[i] == secret[i]) {
                ++bulls;
                continue;
            }
            bucks[guess[i] - '0'] += 1;
            bucks[secret[i] - '0'] -= 1;
        }

        for (int i : bucks) {
            if (i > 0) cows += i;
        }

        cows = (int)guess.size() - bulls - cows;
        ostringstream strio;
        strio << bulls << "A" << cows << "B";
        return strio.str();
    }
};

// Version 2
class Solution {
public:
    string getHint(string secret, string guess) {
        int bulls{0}, cows{0};
        array<int, 10> bucks;
        bucks.fill(0);

        for (size_t i = 0; i < secret.size(); ++i) {
            if (guess[i] == secret[i]) {
                ++bulls;
                continue;
            }
            bucks[guess[i] - '0'] += 1;
            bucks[secret[i] - '0'] -= 1;
        }

        for (int i : bucks) {
            if (i < 0) cows += i;
        }

        cows = (int)guess.size() - bulls + cows;
        ostringstream strio;
        strio << bulls << "A" << cows << "B";
        return strio.str();
    }
};