选择题反选效果分析 | 豆包MarsCode AI刷题

79 阅读3分钟

选择题反选效果分析

问题描述

小U正在检查某同学的选择题答案。试卷共有 n 道题目,每道题目只有两个选项 A 和 B。当前小U手上有两组答案:

  1. s:该同学的原始答案。
  2. t:标准答案。

小U想知道,如果将该同学的所有答案都反选(即:如果某题的答案是 A 则改成 B,如果是 B 则改成 A),那么在反选之后,正确的答案数量是否会增加?具体结果有三种可能:

  1. 如果反选后的正确答案数 增加,输出 "yes"。
  2. 如果反选后的正确答案数 不变,输出 "draw"。
  3. 如果反选后的正确答案数 减少,输出 "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'

算法设计

  1. 初始化变量:创建两个字符数组分别存储学生的答案和标准答案。
  2. 计算初始匹配数:遍历学生答案和标准答案,当两者不匹配时,计数器减一。这是因为不匹配意味着反选后会变成匹配,所以初始匹配数等于总题目数减去不匹配数。
  3. 判断结果:
    • 如果初始匹配数乘以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()
}

在这个版本中,我们直接使用字符串的索引来访问字符,从而避免了中间的类型转换步骤。这种方法不仅保持了原有的时间和空间复杂度,而且可能因为减少了内存分配而略微提高了运行速度。