难度中等126收藏分享切换为英文接收动态反馈
给你一个整数数组 arr
和一个目标值 target
,请你返回一个整数 value
,使得将数组中所有大于 value
的值变成 value
后,数组的和最接近 target
(最接近表示两者之差的绝对值最小)。
如果有多种使得和最接近 target
的方案,请你返回这些整数中的最小值。
请注意,答案不一定是 arr
中的数字。
Go
/*
* @Description:1300
* @Version: 2.0
* @Author: kingeasternsun
* @Date: 2021-02-23 17:12:38
* @LastEditors: kingeasternsun
* @LastEditTime: 2021-02-24 10:25:50
* @FilePath: \1300findBestValue\1300.go
*/
package leetcode
import "sort"
/*
分别找小于 target 或 大于targe的组合
1. arr排序
2. 求前缀和
3. 二分查找
*/
func findBestValue1(arr []int, target int) int {
if len(arr) == 0 {
return 0
}
sort.Ints(arr)
preSum := make([]int, len(arr))
for i := range arr {
preSum[i] = arr[i]
if i > 0 {
preSum[i] += preSum[i-1]
}
}
res, diff := 0, target
for i := 0; i <= arr[len(arr)-1]; i++ {
id := sort.SearchInts(arr, i+1) //查询比i大的
sum := (len(arr) - id) * i //arr[id..]都变为 i
if id > 0 {
sum += preSum[id-1]
}
if sum == target {
return i
}
if abs(sum-target) < diff {
res = i
diff = abs(sum - target)
}
}
return res
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
/*
分别找小于 target 或 大于targe的组合
1. arr排序
2. 求前缀和
3. 双重二分查找 12ms 5.5MB
*/
func findBestValue(arr []int, target int) int {
if len(arr) == 0 {
return 0
}
sort.Ints(arr)
preSum := make([]int, len(arr))
for i := range arr {
preSum[i] = arr[i]
if i > 0 {
preSum[i] += preSum[i-1]
}
}
//查询大于等于 target 的最小value
//这里初始值比较重要,left要从0开始,right的最大值就是arr的最大值,更大是没用的
left, right := 0, arr[len(arr)-1]
best, sum := 0, 0
for left <= right {
mid := (right-left)/2 + left
sum = computeSum(arr, preSum, mid)
if sum == target {
return mid
}
if sum > target {
best, right = mid, mid-1
} else {
best, left = mid, mid+1
}
}
best2 := 0
if sum > target {
best2 = best - 1
} else {
best2 = best + 1
}
sum2 := computeSum(arr, preSum, best2)
if abs(sum-target) < abs(sum2-target) {
return best
}
if abs(sum-target) > abs(sum2-target) {
return best2
}
if best < best2 {
return best
}
return best2
}
func computeSum(arr, preSum []int, mid int) int {
id := sort.SearchInts(arr, mid+1) //查询大于mid的第一个位置
sum := (len(arr) - id) * mid // 大于mid的都变为mid,也就是 arr[id..]都变为 mid
if id > 0 {
sum += preSum[id-1]
}
return sum
}
难度中等166收藏分享切换为英文接收动态反馈
传送带上的包裹必须在 D 天内从一个港口运送到另一个港口。
传送带上的第 i
个包裹的重量为 weights[i]
。每一天,我们都会按给出重量的顺序往传送带上装载包裹。我们装载的重量不会超过船的最大运载重量。
返回能在 D
天内将传送带上的所有包裹送达的船的最低运载能力。
go
/*
* @Description: 1011
* @Version: 2.0
* @Author: kingeasternsun
* @Date: 2021-02-24 10:24:31
* @LastEditors: kingeasternsun
* @LastEditTime: 2021-02-24 10:53:33
* @FilePath: \1011shipWithinDays\1011.go
*/
package leetcode
func shipWithinDays(weights []int, D int) int {
beg := 1 //这个最小值必须是 weights中的最大值,不然这个货物有可能永远都无法上运输带
end := 0
best := 0
for _, v := range weights {
end += v
if v > beg {
beg = v
}
}
for beg <= end {
mid := (end-beg)/2 + beg
if match(weights, D, mid) {
best, end = mid, mid-1
} else {
beg = mid + 1
}
}
return best
}
// mid 每日运输多少个
func match(weights []int, D, mid int) bool {
days := 1
curWight := 0
for _, v := range weights {
if curWight+v > mid { //当天装不下了,放到下一天装
days++
curWight = v
if days > D {
return false
}
} else {
curWight += v
}
}
return true
}
rust
/*
* @Description:
* @Version: 2.0
* @Author: kingeasternsun
* @Date: 2021-02-24 11:00:14
* @LastEditors: kingeasternsun
* @LastEditTime: 2021-02-24 11:13:08
* @FilePath: \1011shipWithinDays\ship_within_days\src\lib.rs
*/
pub struct Solution;
impl Solution {
/*
二分法,转为是否存在一个threshold,连续子数组的和 不大于 threadhold 的情况下,分为 m 个
12ms 2.5MB //跟410题型一样
*/
pub fn ship_within_days(nums: Vec<i32>, m: i32) -> i32 {
if nums.len()==0{
return 0
}
let mut beg = nums.iter().max().unwrap().clone() ;
let mut end: i32 = nums.iter().sum();
let mut best = 0;
while beg<=end{
let mid = (end - beg)/2+beg;
if Self::exist(&nums, m, mid){
best = mid;
end = mid-1;
}else{
beg = mid+1;
}
}
return best
}
//判断按照 threshold 是否可以分为 最多m 份
pub fn exist(nums: &Vec<i32>, m: i32, threshold: i32) -> bool {
let mut cur_day = 1; //当前第几天
let mut cur_weight = 0;
for v in nums {
if cur_weight + v > threshold {
cur_day += 1;
cur_weight = *v;
if cur_day > m {
return false;
}
}else{
cur_weight += v;
}
}
true
}
}
#[cfg(test)]
mod tests {
use crate::Solution;
#[test]
fn it_works() {
assert_eq!(
Solution::ship_within_days(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 5),
15
);
assert_eq!(Solution::ship_within_days(vec![3, 2, 2, 4, 1, 4], 3), 6);
assert_eq!(Solution::ship_within_days(vec![1, 2, 3, 1, 1], 4), 3);
}
}
难度中等378收藏分享切换为英文接收动态反馈
峰值元素是指其值大于左右相邻值的元素。
给你一个输入数组 nums
,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞
。
go
/*
* @Description:
* @Version: 2.0
* @Author: kingeasternsun
* @Date: 2021-02-24 11:30:48
* @LastEditors: kingeasternsun
* @LastEditTime: 2021-02-24 11:55:33
* @FilePath: \162findPeakElement\162.go
*/
package leetcode
//https://talkgo.org/t/topic/1667/18 三分法
func findPeakElement(nums []int) int {
if len(nums) == 1 {
return 0
}
beg := 0
end := len(nums)
for beg < end-1 {
lmid := (end-beg)/2 + beg
rmid := (end-lmid)/2 + lmid
if nums[lmid] >= nums[rmid] {
end = rmid
} else {
beg = lmid
}
}
if nums[beg] > nums[end] {
return beg
}
return end
}