选择题反选效果分析
问题描述
小U正在检查某同学的选择题答案。试卷共有 n 道题目,每道题目只有两个选项 A 和 B。当前小U手上有两组答案:
- s:该同学的原始答案。
- t:标准答案。
小U想知道,如果将该同学的所有答案都反选(即:如果某题的答案是 A 则改成 B,如果是 B 则改成 A),那么在反选之后,正确的答案数量是否会增加?具体结果有三种可能:
- 如果反选后的正确答案数 增加,输出 "yes"。
- 如果反选后的正确答案数 不变,输出 "draw"。
- 如果反选后的正确答案数 减少,输出 "no"。
测试样例
样例1
输入:n = 2,s = "AB",t = "AA"
输出:'draw'
样例2
输入:n = 3,s = "BAA",t = "ABB"
输出:'yes'
样例3
输入:n = 4,s = "ABAB",t = "BABA"
输出:'yes'
算法设计
- 初始化变量:创建两个字符数组分别存储学生的答案和标准答案。
- 计算初始匹配数:遍历学生答案和标准答案,当两者不匹配时,计数器减一。这是因为不匹配意味着反选后会变成匹配,所以初始匹配数等于总题目数减去不匹配数。
- 判断结果:
- 如果初始匹配数乘以2大于总题目数,说明反选后正确答案数量会增加,返回 "yes"。
- 如果初始匹配数乘以2等于总题目数,说明反选前后正确答案数量不变,返回 "draw"。
- 其他情况,说明反选后正确答案数量不会增加,返回 "no"。
这种方法简洁且直接地解决了问题,通过简单的数学逻辑判断出反选后正确答案数量的变化趋势。
复杂度
时间复杂度
- 字符串比较:对于每一对字符串 s 和 t,我们需要逐个字符进行比较,以确定有多少个字符不匹配。这个过程的时间复杂度为 O(n),其中 n 是字符串的长度。
- 条件判断:在比较完成后,我们还需要执行一次条件判断来决定输出的结果。这个步骤的时间复杂度为 O(1)。 因此,整体的时间复杂度为 O(n)。
空间复杂度
- 临时变量:我们在函数内部定义了一些局部变量,包括 ss, tt, count。这些变量占用的空间与输入大小无关,所以空间复杂度为 O(1)。
代码
package main
import "fmt"
func solution(n int, s string, t string) string {
ss := []byte(s)
tt := []byte(t)
count := n
for i := 0; i < n; i++ {
if ss[i] == tt[i] {
count--
}
}
switch {
case count*2 > n:
return "yes"
case count*2 == n:
return "draw"
default:
return "no"
}
}
测试
func main() {
fmt.Println(solution(2, "AB", "AA") == "draw")
fmt.Println(solution(3, "BAA", "ABB") == "yes")
fmt.Println(solution(4, "ABAB", "BABA") == "yes")
}
优化
当前实现已经相当简洁且高效,主要依赖于单次线性扫描来计算不匹配的字符数量。然而,考虑到问题的本质是在比较两组答案之间的差异,我们实际上并不需要显式地将字符串转换成字节数组来进行比较。可以直接用字符串方法或者简单的字符比较来达到同样的效果。
优化后的代码
package main
import (
"fmt"
"strings"
)
func solution(n int, s string, t string) string {
mismatchCount := 0
for i := 0; i < n; i++ {
if s[i] != t[i] {
mismatchCount++
}
}
switch {
case mismatchCount*2 > n:
return "yes"
case mismatchCount*2 == n:
return "draw"
default:
return "no"
}
}
func checkSolution() {
testCases := []struct {
n int
s string
t string
want string
}{
{2, "AB", "AA", "draw"},
{3, "BAA", "ABB", "yes"},
{4, "ABAB", "BABA", "yes"},
}
for _, tc := range testCases {
got := solution(tc.n, tc.s, tc.t)
if got != tc.want {
fmt.Printf("FAIL: Expected %v, got %v\n", tc.want, got)
} else {
fmt.Printf("PASS: %v\n", got)
}
}
}
func main() {
checkSolution()
}
在这个版本中,我们直接使用字符串的索引来访问字符,从而避免了中间的类型转换步骤。这种方法不仅保持了原有的时间和空间复杂度,而且可能因为减少了内存分配而略微提高了运行速度。