2021-08-19:超级洗衣机。假设有 n 台超级洗衣机放在同一排上。开始的时候,每台洗衣机内可能有一定量的衣服,也可能是空的。在每一步操作中,你可以选择任意 m (1 ≤ m ≤ n) 台洗衣机,与此同时将每台洗衣机的一件衣服送到相邻的一台洗衣机。给定一个非负整数数组代表从左至右每台洗衣机中的衣物数量,请给出能让所有洗衣机中剩下的衣物的数量相等的最少的操作步数。如果不能使每台洗衣机中衣物的数量相等,则返回 -1。
福大大 答案2021-08-19:
这道题是见过就会,没见过就不会。
首先看能否平均分配。如果不能平均分配,就不进行下一步了;如果能平均分配,就下一步。
情况一,+a、i、-b,a正和b正取最大值。
情况二,+a、i、+b,a正和b正取最大值。
情况三,-a、i、-b,a正+b正。
情况四,-a、i、+b,a正和b正取最大值。
遍历数组,取最大值就是需要的返回值。
代码里第2种方法,数组的每个元素减去了平均值,方便计算。
时间复杂度:O(N)。
额外空间复杂度:O(1)。
代码用golang编写。代码如下:
package main import "fmt" func main() { arr := []int{1, 2, 3, 4, 5} ret := findMinMoves1(arr) fmt.Println(ret) ret = findMinMoves2(arr) fmt.Println(ret) } func findMinMoves1(arr []int) int { if len(arr) == 0 { return 0 } size := len(arr) sum := 0 for i := 0; i < size; i++ { sum += arr[i] } if sum%size != 0 { return -1 } avg := sum / size leftSum := 0 ans := 0 for i := 0; i < len(arr); i++ { leftRest := leftSum - i*avg rightRest := (sum - leftSum - arr[i]) - (size-i-1)*avg if leftRest < 0 && rightRest < 0 { ans = getMax(ans, Abs(leftRest)+Abs(rightRest)) } else { ans = getMax(ans, getMax(Abs(leftRest), Abs(rightRest))) } leftSum += arr[i] } return ans } func findMinMoves2(arr []int) int { if len(arr) == 0 { return 0 } size := len(arr) sum := 0 for i := 0; i < size; i++ { sum += arr[i] } if sum%size != 0 { return -1 } avg := sum / size sum = 0 //数组每个元素全部减去平均值 for i := 0; i < size; i++ { arr[i] -= avg sum += arr[i] } leftSum := 0 ans := 0 for i := 0; i < len(arr); i++ { leftRest := leftSum rightRest := sum - leftSum - arr[i] if leftRest < 0 && rightRest < 0 { ans = getMax(ans, Abs(leftRest)+Abs(rightRest)) } else { ans = getMax(ans, getMax(Abs(leftRest), Abs(rightRest))) } leftSum += arr[i] } //数组恢复 for i := 0; i < size; i++ { arr[i] += avg } return ans } func Abs(a int) int { if a < 0 { return -a } else { return a } } func getMax(a int, b int) int { if a > b { return a } else { return b } }
执行结果如下: