299.猜数字游戏,新发明了词儿——正负选择

本文介绍了一个简单的LeetCode题目——猜数字游戏,通过哈希表和反证法巧妙解决。文章详细解析了如何利用直接寻址表统计公牛和奶牛数量,以及Go语言和Java实现的代码示例。

今天分享一个LeetCode题,题号是299,标题是猜数字游戏,题目标签是哈希表,题目难度是简单。

这个题是简单题,但里面的思路很有意思,用到了反证法。

题目描述

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

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

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

示例 1:

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

输出: "1A3B"

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

示例 2:

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

输出: "1A1B"

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

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

解题

当我做这道题的时候,有点过分关注公牛和奶牛数量的统计,忽略掉了既不是公牛也不是奶牛的数量统计。

当然不是说仅仅关注公牛和奶牛的数量统计而不能得到答案,是因为我后面想到的一个优化,需要使用到其它性质的数字。

既然题目标签是哈希表,而且题目描述挺适合使用直接寻址表,使用的输入示例都是0~9组成的,可以直接创建10个空间的数组,分别放置0~9

直接寻址表也是哈希表,适合于不是很散的范围使用。

我们假设输入示例是“1123”“0111”,公牛数字的统计很简单,遍历一次,判断相同位置上的数字是否相等;而奶牛数字的统计需要借助两个直接寻址表,分别统计两个输入字符串中不是公牛数字的数量。

两个直接寻址表

但我想要一个直接寻址表应该怎么办呢?

可以借助既不是公牛也不是奶牛的数量统计。

还是刚才的示例“1123”“0111”,在“1123”中可以看到‘2’‘3’不属于公牛数字和奶牛数字,可以统计到两者不属于的数量。

如果得到了公牛数量,也得到了两者不属于的数量,就可以得到奶牛的数量。

这是因为公牛数量 + 奶牛数量 + 两者不属于的数量,刚好等于一个字符串“1123”的长度。

既然是使用一个直接寻址表,怎么才能得到‘2’‘3’呢?

这时候我们就需要一个正负判断了,可以将“1123”中所有的数字都是正数,而“0111”中所有的数字都是负数。公牛数字在同一个位置上相等,而奶牛数字有了正负可以互相抵消掉了,剩下的就是不属于公牛和奶牛的数字了。

正负选择

前几天分享的文章 (天际线问题 和 完美矩形) 也有类似的小技巧,正负选择,例如遇左边界 (正) ,高度入堆;遇右边界 (负) ,高度出堆。

以后看题的时候,遇到类似的情况,一定要能巧妙地想到这点。

Java代码
class Solution {
    public String getHint(String secret, String guess) {
        int len = secret.length();
        int A = 0; // 公牛数量
        int B = 0; // 奶牛数量
        // 创建直接寻址表
        int[] address = new int[10]; // secret和guess奶牛数字的相互抵消
        for (int i = 0; i < len; i++) {
            if (secret.charAt(i) == guess.charAt(i)) A++;
            else {
                address[secret.charAt(i) - '0']++;
                address[guess.charAt(i) - '0']--;
            }
        }
        for (int addr : address)
            if (addr > 0)
                B += addr;
        B = len - A - B;
        return A + "A" + B + "B";
    }
}
Go语言代码
import (
    "fmt"
)

func getHint(secret string, guess string) string {
    len := len(secret)
    A := 0 // 公牛统计
    B := 0 // 奶牛统计
    // 创建直接寻址表
    address := [10]int{0}
    for i := 0; i < len; i++ {
        if secret[i] == guess[i] {
            A++
            continue
        }
        address[secret[i]-'0']++
        address[guess[i]-'0']--
    }
    for _, addr := range address {
        if addr > 0 {
            B += addr
        }
    }
    B = len - A - B
    // 字符串拼接
    return fmt.Sprint(A, "A", B, "B")
}
Go语言执行结果
执行用时 : 0 ms , 在所有 Go 提交中击败了 100.00% 的用户
内存消耗 : 2.3 MB , 在所有 Go 提交中击败了 75.00% 的用户

Java提交之后,执行结果有点惨不忍睹,一度怀疑这算法不是题目标签中更优秀的算法,可能前面提交的人太多,相同的执行用时已经赶不上前面的了。

为了Java和Golang有明显的对比,Java就贴上执行用时和内存消耗。

执行用时 : 6 ms
内存消耗 : 38.4 MB

通过执行结果,Golang的执行用时差别不是很大,而消耗内存切实很省空间。

### 回答1: 个人差距不足及提升举措可以用 "自我提升策略" 来表示。 举例: - 通过学习和研究来提升自己的专业知识和技能 - 多参加培训和课程来增加自己的经验和能力 - 寻找机会来挑战自己并不断提高自己 - 通过认真观察和反思自己的表现来发现问题并改进 - 请教专家和导师来获得指导和建议 ### 回答2: 个人差距不足是指在某些方面与他人相比存在的不足之处。对于个人差距不足的改进,可以采取以下措施: 首先,持续学习和提高自我素质。个人差距往往源于知识、技能和经验的不足。通过不断学习,可以补充自己的知识储备,培养新的技能,增加工作经验,从而提高个人的竞争力。 其次,与他人互相学习与交流。没有人是完美无缺的,每个人都有自己擅长的领域。通过与他人的交流学习,可以借鉴他们的优点和经验教训,找到自己的不足之处并加以改进。 再次,制定明确的目标和计划。个人差距不足的改进需要有一个具体的目标和可执行的计划。制定一个合理的时间表,并根据实际情况进行调整,使自己在一定的时间内能够不断进步并实现目标。 最后,保持积极的心态和坚持不懈的努力。改进个人差距不是一蹴而就的过程,需要耐心和坚持不懈的努力。保持积极的心态,相信自己可以克服困难,并且持续不断地努力,才能最终实现个人的提升和突破。 总之,个人差距不足是一种机会,只要我们勇于面对并采取适当的措施,就可以不断提升自己,实现个人的成长和发展。 ### 回答3: 个人差距不足是每个人成长过程中普遍存在的问题。我也不例外,有时可能会感到技能、知识或经验方面存在不足。为了不断提升自我,我采取了一些举措。 首先,我认识到学习是不断进步的关键。我积极参加培训课程、研讨会和工作坊,以扩展我的技能和知识。此外,我也通过阅读书籍、文章和专业期刊来不断学习新知,并将其运用到工作中。 其次,我意识到自我反思是提升的重要一环。在工作中,我常常回顾自己的表现,找出不足之处,然后制定相应的改进计划。同时,我也会向他人寻求反馈,听取他们的意见和建议,以便改进自己的工作能力。 此外,我注重保持积极的心态和良好的工作习惯。我相信积极的思维方式可以激发潜力,并促使个人进步。为了养成良好的工作习惯,我注重时间管理、任务分配和目标设定。通过这些举措,我能更好地掌握时间,提高工作效率。 最后,我也意识到自我激励的重要性。我设立个人目标,并不断努力实现。我相信自我激励可以帮助我克服挑战和困难,继续向前推进。 总之,个人差距是一种普遍现象。为了提升自己,我将积极学习和反思,并保持积极心态和良好工作习惯。同时,自我激励也是不可或缺的。通过这些举措,我相信我能够不断提升自己的能力,并取得更大的进步。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值