小米OJ第20题Go语言实现:
问题链接:https://code.mi.com/problem/list/view?id=20
描述
等差数列是常见数列的一种,如果一个数列从第二项起,每一项与它的前一项的差等于同一个常数,这个数列就叫做等差数列,而这个常数叫做等差数列的公差,公差常用字母d表示。即对于数列S,它满足了(S[i]-S[i-1]) = d (i \gt 1)(S[i]−S[i−1])=d(i>1)。 显然,一个数字无法构成等差数列,而任意两个数字可以形成一个等差数列。 这里给出了一个长度为N (0 \lt N \lt 200)N(0<N<200)的数字序列,每个位置有一个整数(-100 \le \text{整数} \le 100)(−100≤整数≤100),需要找到这个数字序列里包含多少个等差数列,序列顺序固定,无需排序。 输入数据格式:\text{S[0] S[1] S[2] … S[N]}S[0] S[1] S[2] … S[N](以半角空格符分隔,N \gt 1N>1) 输出数据格式:等差数列数量 MM; 其中数列 SS 的项为整数
请注意时间复杂度的限制。
输入
输入一个数列[ 2 7 4 5 6 ],该数列包含等差数列: [ 2 7 ] [ 2 4 ] [ 2 5 ] [ 2 6 ] [ 7 4 ] [ 7 5 ] [ 7 6 ] [ 4 5 ] [ 4 6 ] [ 5 6 ] [ 2 4 6 ] [ 4 5 6 ]
输出
上例共包含12组等差数列,故应输出12
输入样例
2 7 4 5 6
3 3 3 3
复制样例
输出样例
12
11
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func solution20(line string) string {
numberArrray := strings.Split(line, " ")
numbers := make([]int, len(numberArrray))
for i, v := range numberArrray {
numbers[i], _ = strconv.Atoi(v)
}
var result = 0
listArray := make([][]*int, 0)
tempResult := make([]*int, 0)
DFS(listArray, tempResult, numbers, 0, &result);
return strconv.Itoa(result)
}
func DFS(resultArray [][]*int, tempArray []*int, numbers []int, start int, result *int) {
resultArray = append(resultArray, tempArray)
judgeResult := isCorrectArray(tempArray)
if !judgeResult && len(tempArray) > 2 {
return
}
if judgeResult{
*result = *result + 1
}
for i := start; i < len(numbers); i++ {
tempArray = append(tempArray, &numbers[i])
DFS(resultArray, tempArray, numbers, i+1, result);
tempArray = tempArray[:len(tempArray)-1]
}
}
func isCorrectArray(args []*int) bool {
if len(args) <= 1 {
return false
}
if len(args) == 2 {
return true
}
d := *args[1] - *args[0]
for i := 2; i < len(args); i++ {
if *args[i]-*args[i-1] != d {
return false
}
}
return true
}
func main() {
r := bufio.NewReaderSize(os.Stdin, 20480)
for line, _, err := r.ReadLine(); err == nil; line, _, err = r.ReadLine() {
fmt.Println(solution20(string(line)))
}
}
此题关键点
- 排列组合的展示,给定了一个序列,要求输出所有组合或者序列,这里没有顺序的要求,故要求展示其所有的组合,共有种。有暴力法、DFS法,二进制法(即01100,代表只有第2和第3个,每次二进制加1,即得到一种组合)(欢迎补充)
- 数组的判定,只需根据等差数组的定义来即可
- 时间复杂度要求,起初的思路是找出所有的组合情况,最后统一判断,但运行结果超时,即对于序列2 7 4 5 6,先找出所有的可能性,共15种,再对这15种进行判断,时间复杂度不符合要求。
- 采用DFS之后需要进行剪枝,例如2 7 4这样已经不符合等差数列要求的序列,后面的就不要展示出来了,因为其肯定不满足等差数列定义,可以直接砍掉后面的2 7 4 5和2 7 4 6 以及2 7 4 5 6,同理可以减掉多种情况,一方面较少了DFS遍历的深度即数量,另一方面也减少了等差数组的判定,最终时间复杂度符合要求。
注:
该类问题有多种变体,现记录如下,之后需要分类解决
5. 全排列问题 {a,b,c},给出所有的排列,共个
6. 从M个序列中任取K个,输出所有的可能性。
7. DFS和BFS
8. 未完待续(…)
DSF的常用场景
- 回溯法
- 字典序
例如给定字符数组{‘1’,‘2’,‘3’},按序输出所有的组合,以字典序输出,以下给出关键代码
func DFS(visit []int, tempResult []int, numbers []int, start int) {
if start == len(numbers) {
for j := range tempResult {
fmt.Print("\t", tempResult[j])
}
fmt.Println("")
}
for i := 0; i < len(numbers); i++ {
if visit[i] == 0 {
visit[i] = 1
tempResult[start] = numbers[i]
DFS(visit, tempResult, numbers, start+1);
visit[i] = 0
}
}
}