ARTS LeetCode 718:最长重复子数组

231 阅读2分钟

继续做脑力运动刷LeetCode,今天继续使用go来做开发,随机刷了一道编号718的题:Add Two Numbers,中文名叫最长重复子数组,难度:中等。

题目要求如下:

给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。

示例 1:

输入:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
输出: 3
解释: 
长度最长的公共子数组是 [3, 2, 1]。
说明:

1 <= len(A), len(B) <= 1000
0 <= A[i], B[i] < 100

题目偏简单了,就当熟悉go语言规范了,循环结构和条件语句不熟悉。

官方一共54个test case,放一个最终结果吧

执行用时 : 236 ms, 在所有 Go 提交中击败了 6.60% 的用户 内存消耗 : 3.4 MB, 在所有 Go 提交中击败了 100.00% 的用户

详细信息参考这里 最长重复子数组 - 提交记录 - 力扣 (LeetCode) ,执行时间有点出乎意料。

再去英文版检查一下

Runtime: 184 ms, faster than 5.88% of Go online submissions for Maximum Length of Repeated Subarray. Memory Usage: 3.4 MB, less than 100.00% of Go online submissions for Maximum Length of Repeated Subarray.

详细信息参考这里 Maximum Length of Repeated Subarray - Submission Detail - LeetCode ,一样的效果,执行时间有点太长。

先解释一下思路:

  • 以其中一个数组的遍历作为主循环
  • 开始逐段比较,如果相同就继续
  • 如果失败,重置内循环的计数器j到lastIndexJ
  • 如果内循环的计数器j到头了,那么就记录结果,重置主循环的计数器i到lastIndexI
  • 优化思路时,当发现已有当长度少于之前的结果,就停止或开始下一段的比较
package main

func findLength(A []int, B []int) int {
	var result, lastResult, lastIndexI, lastIndexJ = 0, 0, 0, 0
	for i, j := 0, 0; i < len(A); {
		if A[i] == B[j] {
			result++
			i++
			j++
			if lastResult < result {
				lastResult = result
			}
		} else {
			i = lastIndexI
			lastIndexJ++
			j = lastIndexJ
			result = 0
		}
		if j >= len(B) || len(B)-lastIndexJ <= lastResult {
			lastIndexI++
			i = lastIndexI
			if len(A)-i <= lastResult {
				break
			}
			j, lastIndexJ = 0, 0
			result = 0
		}
	}
	return lastResult
}

还有测试用例,大部分取自官方测试用例集合,包含大多数典型情况。

package main

import "testing"

func Test_findLength(t *testing.T) {
	type args struct {
		A []int
		B []int
	}
	tests := []struct {
		name string
		args args
		want int
	}{
		{"第一个测试", args{[]int{1, 2, 3, 2, 1}, []int{3, 2, 1, 4, 7}}, 3},
		{"第二个测试", args{[]int{}, []int{}}, 0},
		{"第三个测试", args{[]int{1}, []int{1}}, 1},
		{"第四个测试", args{[]int{1}, []int{2}}, 0},
		{"第五个测试", args{[]int{0, 0, 0, 0, 1}, []int{1, 0, 0, 0, 0}}, 4},
		{"第六个测试", args{[]int{0, 0, 0, 0, 0}, []int{0, 0, 0, 0, 0}}, 5},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			if got := findLength(tt.args.A, tt.args.B); got != tt.want {
				t.Errorf("findLength() = %v, want %v", got, tt.want)
			}
		})
	}
}

收获

这次这个有点花时间和思路,主要是优化计算时间上面,虽然结果对了,貌似计算时长比平均值差不少,今天有空再看看标准解法,看看有没有啥收获。