1. 检查整数及其两倍数是否存在

这道题应该也是个送分题,快的人一两分钟就提交通过了,就是 O(N2) 的复杂度,然后分别对比前后是否成 2 倍关系即可:

[[email protected]]# cat Q1.go
func checkIfExist(arr []int) bool {
    var (
        i, j   int
        length = len(arr)
    )

    for i = 0; i < length; i++ {
        for j = i + 1; j < length; j++ {
            if arr[i] == arr[j]*2 || arr[i]*2 == arr[j] {
                return true
            }
        }
    }
    return false
}

2. 制造字母异位词的最小步骤数

这道题目的意思不是很好理解,我带猜的情况下算是猜对了,其实就是你可以选择任意字母替换字符串 t 中的字符,然后最终的结果就是 s 和 t 不一样,但是所含的字母的个数是一样的,例如示例一中的 s 和 t 最终都含有 1 个 a 和 2 个 b。

那这样就简单了,直接比较原始的 s 和 t 中不同的字母数量有几个,例如 ab 和 bc,不同的字母值有一个 a 和 c,这里可以直接用一个 map 来计数:

[[email protected]]# cat Q2.go
func minSteps(s string, t string) int {
    var commonChar = 0
    var charA = map[uint8]int{}

    for i := 0; i < len(s); i++ {
        charA[s[i]]++
    }
    for i := 0; i < len(t); i++ {
        charA[t[i]]--
    }
    for _, v := range charA {
        commonChar += abs(v)
    }
    return commonChar / 2
}

最后这里之所以要减去一半是因为不同的字母我这里算了两次,例如 ab 和 bc,其中 a 最终的数值是 1,c 的数值是 -1,按道理,其实我只需要累加非负部分即可,但是,我觉得最后减半代码更好看,所以就这么做了。

3. 推文计数

这道题目是道坑壁题,一个是题目意思有一点隐藏,另外一个是提交错误的时候提示的内容是错的,导致最终没有提交正确。这里的注意点有:

一开始我还使用二分查找去寻找 startTime 的上界,然而最终发现根本没必要,遍历都可以通过,然后其实其他就很简单了,本来是道送分题,结果成了进坑题:

[[email protected]]# cat Q3.go
import "sort"

type TweetCounts struct {
    tweets map[string][]int
}

func Constructor() TweetCounts {
    tc := TweetCounts{
        tweets: map[string][]int{},
    }
    return tc
}

func (this *TweetCounts) RecordTweet(tweetName string, time int) {
    this.tweets[tweetName] = append(this.tweets[tweetName], time)
}

func (this *TweetCounts) GetTweetCountsPerFrequency(freq string, tweetName string, startTime int, endTime int) (rst []int) {
    sort.Ints(this.tweets[tweetName])
    var freqSecond = 60
    switch freq {
    case "minute":
        break
    case "hour":
        freqSecond = 3600
    case "day":
        freqSecond = 24 * 3600
    }

    var tweets = this.tweets[tweetName]
    rst = make([]int, (endTime-startTime)/freqSecond+1)
    for i := 0; i < len(tweets); i++ {
        if tweets[i] < startTime {
            continue
        }
        if tweets[i] > endTime {
            return rst

        }
        rst[(tweets[i]-startTime)/freqSecond]++
    }
    return rst
}

4. 参加考试的最大学生数

必须老实说,这道题我没做出来,我一致在考虑回溯,然而,毫无疑问,超时了。然后看了第一的代码之后,原来这是一道 DP。

当知道是 DP 之后,似乎一切都恍然大悟,第二行只依赖于自己和前面一行,是一个很明显的 DP 特征,但是,DP 也推倒不出来。再从代码中看时,一切都了然,原来还是需要遍历一行中的所有状态的,不过人家的遍历写得很有意思,例如,如果记录放置学生的状态,这里使用的是位来表示,如果一个 bit 为 0,表示不放置学生,如果一个 bit 为 1 则表示这个位放置了学生,这样得话,判断左右是否有学生就可以这么做了:

s & (s << 1) == 0 && s & (s >> 1) == 0

至于左前和右前也是同样的道理。最后,这是我修改后的自己的版本:

[[email protected]]# cat Q4.go
func maxStudents(seats [][]byte) int {
    var (
        // 某一行中处于 state i 时,可以坐 stateCount[i] 个学生
        stateCount = make([]int, 256)
        //  前 i 排在第 i 排处于 state j 时可以坐 lineStateCount[i][j] 个学生
        lineStateCount = make([][]int, 9)
        badSeats       = make([]int, 9)
        lenX           = len(seats)
        lenY           = len(seats[0])
        i, j, k        int
        ans            = 0
    )
    for i = 1; i < 256; i++ {
        stateCount[i] = stateCount[i>>1] + (i & 1)
    }
    for i = 0; i <= lenX; i++ {
        lineStateCount[i] = make([]int, 256)
        //for j = 0; j < 256; j++ {
        //    lineStateCount[i][j] = 0
        //}
    }
    for i = 0; i < lenX; i++ {
        badSeats[i] = 0
        for j = 0; j < lenY; j++ {
            if seats[i][j] == '#' {
                badSeats[i] |= 1 << j
            }
        }
    }
    lineStateCount[0][0] = 0
    for i = 0; i < lenX; i++ {
        // 对于第 i 排的 state j 作判断
        for j = 0; j < 1<<lenY; j++ {
            // 没有坏座位: j&badSeats[i] == 0
            // 对于每个坐了人的座位,左右都没有人:j&j>>1 == 0 && j&j<<1 == 0
            if j&badSeats[i] == 0 && j&(j>>1) == 0 && j&(j<<1) == 0 {
                for k = 0; k < 1<<lenY; k++ {
                    // 对于每个坐了人的座位,左前和右前都没有人
                    if j&(k>>1) == 0 && j&(k<<1) == 0 {
                        // stateCount[j]:状态 j 下可以这一排可以坐多少人
                        lineStateCount[i+1][j] = max(lineStateCount[i+1][j], lineStateCount[i][k]+stateCount[j])
                    }
                }
            }
        }
    }
    for i = 0; i < 1<<lenY; i++ {
        ans = max(ans, lineStateCount[lenX][i])
    }
    return ans
}

5. 小结

这一次的提交很失败,一个半小时也只写了 2 道,除开第 3 道或许和系统有关之外,第四道应该是再给一小时也通过不了的,看别人的评论,似乎是以前有类似的题目出现过,这可能可以认为是见识不够的缘故(且当是安慰一下自己吧)。