Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >2021-04-04:给定一个非负数组arr,和一个正数m的最大值。

2021-04-04:给定一个非负数组arr,和一个正数m的最大值。

原创
作者头像
福大大架构师每日一题
修改于 2021-04-06 03:26:02
修改于 2021-04-06 03:26:02
8730
举报

2021-04-04:给定一个非负数组arr,和一个正数m。 返回arr的所有子序列中累加和%m之后的最大值。

福大大 答案2021-04-04:

自然智慧即可。

1.递归,累加和。

2.动态规划,累加和。

3.动态规划,累加和%m。

4.双向动态规划,累加和%m。

代码用golang编写。代码如下:

代码语言:txt
AI代码解释
复制
package main

import (
    "fmt"
    "math/rand"
    "sort"
    "time"
)

func main() {
    rand.Seed(time.Now().Unix())
    const TOTAL = 500
    RightCount := 0
    for i := 0; i < TOTAL; i++ {
        arr := NewRandArr()
        m := rand.Intn(200) + 1
        fmt.Println(arr, m)
        ret1 := max1(arr, m)
        fmt.Println("1.递归,累加和:", ret1)
        ret2 := max2(arr, m)
        fmt.Println("2.动态规划,累加和:", ret2)
        ret3 := max3(arr, m)
        fmt.Println("3.动态规划,累加和%m:", ret3)
        ret4 := max4(arr, m)
        fmt.Println("4.双向动态规划,累加和%m:", ret4)
        fmt.Println("---------------------")
        if ret1 == ret2 && ret1 == ret3 && ret1 == ret4 {
            RightCount++
        }
    }
    fmt.Println("总数:", TOTAL)
    fmt.Println("正确:", RightCount)
}

//递归,算出所有子序列的累加和
func max1(arr []int, m int) int {
    set := make(map[int]struct{})
    process(arr, 0, 0, set)
    max := 0
    for sum, _ := range set {
        max = getMax(max, sum%m)
    }
    return max
}

func process(arr []int, index int, sum int, set map[int]struct{}) {
    if index == len(arr) {
        set[sum] = struct{}{}
    } else {
        process(arr, index+1, sum, set)
        process(arr, index+1, sum+arr[index], set)
    }
}
func getMax(a int, b int) int {
    if a > b {
        return a
    } else {
        return b
    }
}

//2.动态规划,算出所有的累加和
func max2(arr []int, m int) int {
    sum := 0
    N := len(arr)
    for i := 0; i < N; i++ {
        sum += arr[i]
    }
    dp := make([][]bool, N)
    for i := 0; i < N; i++ {
        dp[i] = make([]bool, sum+1)
    }
    for i := 0; i < N; i++ {
        dp[i][0] = true
    }
    dp[0][arr[0]] = true
    for i := 1; i < N; i++ {
        for j := 1; j <= sum; j++ {
            dp[i][j] = dp[i-1][j]
            if j-arr[i] >= 0 {
                dp[i][j] = dp[i][j] || dp[i-1][j-arr[i]]
            }
        }
    }
    ans := 0
    for j := 0; j <= sum; j++ {
        if dp[N-1][j] {
            ans = getMax(ans, j%m)
        }
    }
    return ans
}

//3.动态规划,算出所有的模m的累加和。数组长度巨大,m不大。
func max3(arr []int, m int) int {
    N := len(arr)
    // 0...m-1
    dp := make([][]bool, N)
    for i := 0; i < N; i++ {
        dp[i] = make([]bool, m)
    }
    for i := 0; i < N; i++ {
        dp[i][0] = true
    }
    dp[0][arr[0]%m] = true
    for i := 1; i < N; i++ {
        for j := 1; j < m; j++ {
            // dp[i][j] T or F
            dp[i][j] = dp[i-1][j]
            cur := arr[i] % m
            if cur <= j {
                dp[i][j] = dp[i][j] || dp[i-1][j-cur]
            } else {
                dp[i][j] = dp[i][j] || dp[i-1][m+j-cur]
            }
        }
    }
    ans := 0
    for i := 0; i < m; i++ {
        if dp[N-1][i] {
            ans = i
        }
    }
    return ans
}

// 如果arr的累加和很大,m也很大
// 但是arr的长度相对不大
func max4(arr []int, m int) int {
    if len(arr) == 1 {
        return arr[0] % m
    }
    mid := (len(arr) - 1) / 2

    sortSet1 := make(map[int]struct{})
    process4(arr, 0, 0, mid, m, sortSet1)
    sortSet2 := make(map[int]struct{})
    process4(arr, mid+1, 0, len(arr)-1, m, sortSet2)
    ans := 0

    s1 := make([]int, 0)
    for key, _ := range sortSet1 {
        s1 = append(s1, key)
    }
    sort.Ints(s1)
    //fmt.Println("s1:", s1)

    s2 := make([]int, 0)
    for key, _ := range sortSet2 {
        s2 = append(s2, key)
    }
    sort.Ints(s2)
    //fmt.Println("s2:", s2)

    for _, leftMod := range s1 {
        //ans = getMax(ans, leftMod + sortSet2.floor(m - 1 - leftMod));
        index := NearestIndex2(s2, m-1-leftMod)
        if index >= 0 {
            ans = getMax(ans, leftMod+s2[index])
        } else {
            ans = getMax(ans, leftMod)
        }
    }
    return ans
}

// 在arr上,找满足<=value的最右位置
func NearestIndex2(arr []int, v int) int {
    L := 0
    R := len(arr) - 1
    index := -1 // 记录最右的对号
    for L <= R {
        mid := L + (R-L)>>1
        if arr[mid] <= v {
            index = mid
            L = mid + 1
        } else {
            R = mid - 1
        }
    }
    return index
}

// 从index出发,最后有边界是end+1,arr[index...end]
func process4(arr []int, index int, sum int, end int, m int, sortSet map[int]struct{}) {
    if index == end+1 {
        sortSet[sum%m] = struct {
        }{}
    } else {
        process4(arr, index+1, sum, end, m, sortSet)
        process4(arr, index+1, sum+arr[index], end, m, sortSet)
    }
}

func NewRandArr() []int {
    arrLen := rand.Intn(10) + 5
    arr := make([]int, arrLen)
    for i := 0; i < arrLen; i++ {
        arr[i] = rand.Intn(50)
    }
    return arr
}

执行结果如下:

在这里插入图片描述
在这里插入图片描述

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
2021-02-25:给定一个正数数组arr,请把arr中所有的数分成两个集合。
2021-02-25:给定一个正数数组arr,请把arr中所有的数分成两个集合。如果arr长度为偶数,两个集合包含数的个数要一样多;如果arr长度为奇数,两个集合包含数的个数必须只差一个。请尽量让两个集合的累加和接近,返回最接近的情况下,较小集合的累加和。
福大大架构师每日一题
2021/02/25
2980
2021-02-25:给定一个正数数组arr,请把arr中所有的数分成两个集合。
2021-08-09:给定一个有正、有负、有0的数组arr
2021-08-09:给定一个有正、有负、有0的数组arr,给定一个整数k,返回arr的子集是否能累加出k。1)正常怎么做?2)如果arr中的数值很大,但是arr的长度不大,怎么做?
福大大架构师每日一题
2021/08/09
3270
2021-08-09:给定一个有正、有负、有0的数组arr
2021-10-26:给定一个数组arr,arr[i] = j,表示第i号试题的
2021-10-26:给定一个数组arr,arri = j,表示第i号试题的难度为j。给定一个非负数M。想出一张卷子,对于任何相邻的两道题目,前一题的难度不能超过后一题的难度+M。返回所有可能的卷子种数。
福大大架构师每日一题
2021/10/26
3130
2021-06-16:返回一个数组中,选择的数字不能相邻的情况下, 最大子序列累加和。
2021-06-16:返回一个数组中,选择的数字不能相邻的情况下, 最大子序列累加和。
福大大架构师每日一题
2021/06/16
6230
2021-06-16:返回一个数组中,选择的数字不能相邻的情况下, 最大子序列累加和。
2021-04-03:给定两个字符串str1和str2,想把str2整体插入到str1中的某个
2021-04-03:给定两个字符串str1和str2,想把str2整体插入到str1中的某个位置,形成最大的字典序,返回字典序最大的结果。
福大大架构师每日一题
2021/04/03
5440
2021-04-03:给定两个字符串str1和str2,想把str2整体插入到str1中的某个
2022-03-18:arr数组长度为n, magic数组长度为m 比如 arr = { 3, 1, 4, 5, 7 },如果完全不改变arr中的值, 那么收益
比如 arr = { 3, 1, 4, 5, 7 },如果完全不改变arr中的值,
福大大架构师每日一题
2022/03/18
8020
2021-04-29:给定一个数组 arr,代表一排有分数的气球。每打爆一
2021-04-29:给定一个数组 arr,代表一排有分数的气球。每打爆一个气球都能获得分数,假设打爆气 球 的分数为 X,获得分数的规则如下: 1)如果被打爆气球的左边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为 L;如果被打爆气球的右边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为 R。 获得分数为 L_X_R。 2)如果被打爆气球的左边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为 L;如果被打爆气球的右边所有气球都已经被打爆。获得分数为 L_X。 3)如果被打爆气球的左边所有的气球都已经被打爆;如果被打爆气球的右边有没被打爆的 气球,找到离被打爆气球最近的气球,假设分数为 R;如果被打爆气球的右边所有气球都 已经 被打爆。获得分数为 X_R。 4)如果被打爆气球的左边和右边所有的气球都已经被打爆。获得分数为 X。目标是打爆所有气球,获得每次打爆的分数。通过选择打爆气球的顺序,可以得到不同的总分,请返回能获得的最大分数。【举例】arr = {3,2,5} 如果先打爆3,获得3_2;再打爆2,获得2_5;最后打爆5,获得5;最后总分21 如果先打爆3,获得3_2;再打爆5,获得2_5;最后打爆2,获得2;最后总分18 如果先打爆2,获得3_2_5;再打爆3,获得3_5;最后打爆5,获得5;最后总分50 如果先打爆2,获得3_2_5;再打爆5,获得3_5;最后打爆3,获得3;最后总分48 如果先打爆5,获得2_5;再打爆3,获得3_2;最后打爆2,获得2;最后总分18 如果先打爆5,获得2_5;再打爆2,获得3_2;最后打爆3,获得3;最后总分19 返回能获得的最大分数为50。
福大大架构师每日一题
2021/05/04
3310
2021-04-29:给定一个数组 arr,代表一排有分数的气球。每打爆一
2021-05-08:给定两个非负数组x和hp,长度都是N,再给定一个正数range
2021-05-08:给定两个非负数组x和hp,长度都是N,再给定一个正数range。x有序,xi表示i号怪兽在x轴上的位置;hpi表示i号怪兽的血量 。range表示法师如果站在x位置,用AOE技能打到的范围是: x-range,x+range,被打到的每只怪兽损失1点血量 。返回要把所有怪兽血量清空,至少需要释放多少次AOE技能?
福大大架构师每日一题
2021/05/10
4980
2021-05-08:给定两个非负数组x和hp,长度都是N,再给定一个正数range
2021-11-27:给定一个数组arr,长度为N,做出一个结构,
2021-11-27:给定一个数组arr,长度为N,做出一个结构,可以高效的做如下的查询:
福大大架构师每日一题
2021/11/27
2310
2020-02-24:arr是面值数组,其中的值都是正数且没有重复
福哥答案2020-02-24: 自然智慧即可。 1.递归。有代码。 2.动态规划。dp是二维数组。有代码。 代码用golang编写,代码如下: package main import ( "fmt" ) func main() { arr := []int{1, 2, 3} aim := 8 ret := minCoins1(arr, aim) fmt.Println("1.递归:", ret) ret = minCoins2(arr, aim) fmt.
福大大架构师每日一题
2021/02/24
4240
2020-02-24:arr是面值数组,其中的值都是正数且没有重复
2021-08-10:给定一个正数数组arr,返回arr的子集不能累加
2021-08-10:给定一个正数数组arr,返回arr的子集不能累加出的最小正数。1)正常怎么做? 2)如果arr中肯定有1这个值,怎么做?
福大大架构师每日一题
2021/08/10
3730
2021-08-10:给定一个正数数组arr,返回arr的子集不能累加
2021-04-25:给定一个数组arr,和一个正数M,返回在
福大大 答案2021-04-25: 前缀和+左大右小的双端队列。时间太晚了,所以写得简单。 代码用golang编写。代码如下: package main import ( "container/list" "fmt" ) func main() { arr := []int{1, 2, -3, 4, -5} ret := maxSum(arr, 5) fmt.Println(ret) } // O(N)的解法,最优解 func maxSum(arr []int,
福大大架构师每日一题
2021/05/04
3640
2021-04-25:给定一个数组arr,和一个正数M,返回在
2021-04-29:给定一个数组 arr,代表一排有分数的气球。每打爆一个气球都能获得分数,假设打爆气 球 的分数为 X,获得
2021-04-29:给定一个数组 arr,代表一排有分数的气球。每打爆一个气球都能获得分数,假设打爆气 球 的分数为 X,获得分数的规则如下: 1)如果被打爆气球的左边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为 L;如果被打爆气球的右边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为 R。获得分数为 L*X*R。2)如果被打爆气球的左边有没被打爆的气球,找到离被打爆气球最近的气球,假设分数为 L;如果被打爆气球的右边所有气球都已经被打爆。获得分数为 L*X。3)如果被打爆气球的左边所有的气球都已经被打爆;如果被打爆气球的右边有没被打爆的 气球,找到离被打爆气球最近的气球,假设分数为 R;如果被打爆气球的右边所有气球都 已经 被打爆。获得分数为 X*R。4)如果被打爆气球的左边和右边所有的气球都已经被打爆。获得分数为 X。目标是打爆所有气球,获得每次打爆的分数。通过选择打爆气球的顺序,可以得到不同的总分,请返回能获得的最大分数。【举例】arr = {3,2,5} 如果先打爆3,获得3*2;再打爆2,获得2*5;最后打爆5,获得5;最后总分21 如果先打爆3,获得3*2;再打爆5,获得2*5;最后打爆2,获得2;最后总分18 如果先打爆2,获得3*2*5;再打爆3,获得3*5;最后打爆5,获得5;最后总分50 如果先打爆2,获得3*2*5;再打爆5,获得3*5;最后打爆3,获得3;最后总分48 如果先打爆5,获得2*5;再打爆3,获得3*2;最后打爆2,获得2;最后总分18 如果先打爆5,获得2*5;再打爆2,获得3*2;最后打爆3,获得3;最后总分19 返回能获得的最大分数为50。
福大大架构师每日一题
2021/08/05
3530
​2021-03-30:给定一个整数组成的无序数组arr,值可能正、可能负、可能0。<=K
2021-03-30:给定一个整数组成的无序数组arr,值可能正、可能负、可能0。给定一个整数值K,找到arr的所有子数组里,哪个子数组的累加和<=K,并且是长度最大的。返回其长度。
福大大架构师每日一题
2021/03/30
4930
​2021-03-30:给定一个整数组成的无序数组arr,值可能正、可能负、可能0。<=K
2021-05-06:给定一个二维数组matrix, 你可以从任何位置
2021-05-06:给定一个二维数组matrix, 你可以从任何位置出发,走向上下左右四个方向 。返回能走出来的最长的递增链长度。
福大大架构师每日一题
2021/05/06
5640
2021-05-06:给定一个二维数组matrix, 你可以从任何位置
2022-04-14:小美有一个长度为n的数组, 为了使得这个数组的和尽量大,她向会魔法的小团进行求助。 小团可以选择数组中至多两个不相交的子数组, 并将区间里的数全都变为原来的10倍。 小团想知道他的魔法最多可以帮助小美将数组的和变大到多少?
2022-04-14:小美有一个长度为n的数组, 为了使得这个数组的和尽量大,她向会魔法的小团进行求助。 小团可以选择数组中至多两个不相交的子数组, 并将区间里的数全都变为原来的10倍。 小团想知道他
福大大架构师每日一题
2022/04/14
1.6K0
2021-08-28:给定一个正数数组arr,长度一定大于6(>=7
2021-08-28:给定一个正数数组arr,长度一定大于6(>=7),一定要选3个数字做分割点,从而分出4个部分,并且每部分都有数,分割点的数字直接删除,不属于任何4个部分中的任何一个。 返回有没有可能分出的4个部分累加和一样大,如:{3,2,3,7,4,4,3,1,1,6,7,1,5,2},可以分成{3,2,3}、{4,4}、{1,1,6}、{1,5,2}。分割点是不算的!
福大大架构师每日一题
2021/08/28
2690
2021-08-28:给定一个正数数组arr,长度一定大于6(>=7
2021-04-05:给两个长度分别为M和N的整型数组...
2021-04-05:给两个长度分别为M和N的整型数组nums1和nums2,其中每个值都不大于9,再给定一个正数K。 你可以在nums1和nums2中挑选数字,要求一共挑选K个,并且要从左到右挑。返回所有可能的结果中,代表最大数字的结果。
福大大架构师每日一题
2021/04/05
4670
2021-04-05:给两个长度分别为M和N的整型数组...
2021-04-07:给定一个非负数组arr,长度为N,那么有N-1种方案可以把arr切成左右两部分
2021-04-07:给定一个非负数组arr,长度为N,那么有N-1种方案可以把arr切成左右两部分,每一种方案都有,min{左部分累加和,右部分累加和},求这么多方案中,min{左部分累加和,右部分累加和}的最大值是多少? 整个过程要求时间复杂度O(N)。
福大大架构师每日一题
2021/04/07
3420
2021-04-07:给定一个非负数组arr,长度为N,那么有N-1种方案可以把arr切成左右两部分
2022-01-20: 矩形区域不超过 K 的最大数值和。 给你一个 m
给你一个 m x n 的矩阵 matrix 和一个整数 k ,找出并返回矩阵内部矩形区域的不超过 k 的最大数值和。
福大大架构师每日一题
2022/01/20
2470
推荐阅读
2021-02-25:给定一个正数数组arr,请把arr中所有的数分成两个集合。
2980
2021-08-09:给定一个有正、有负、有0的数组arr
3270
2021-10-26:给定一个数组arr,arr[i] = j,表示第i号试题的
3130
2021-06-16:返回一个数组中,选择的数字不能相邻的情况下, 最大子序列累加和。
6230
2021-04-03:给定两个字符串str1和str2,想把str2整体插入到str1中的某个
5440
2022-03-18:arr数组长度为n, magic数组长度为m 比如 arr = { 3, 1, 4, 5, 7 },如果完全不改变arr中的值, 那么收益
8020
2021-04-29:给定一个数组 arr,代表一排有分数的气球。每打爆一
3310
2021-05-08:给定两个非负数组x和hp,长度都是N,再给定一个正数range
4980
2021-11-27:给定一个数组arr,长度为N,做出一个结构,
2310
2020-02-24:arr是面值数组,其中的值都是正数且没有重复
4240
2021-08-10:给定一个正数数组arr,返回arr的子集不能累加
3730
2021-04-25:给定一个数组arr,和一个正数M,返回在
3640
2021-04-29:给定一个数组 arr,代表一排有分数的气球。每打爆一个气球都能获得分数,假设打爆气 球 的分数为 X,获得
3530
​2021-03-30:给定一个整数组成的无序数组arr,值可能正、可能负、可能0。<=K
4930
2021-05-06:给定一个二维数组matrix, 你可以从任何位置
5640
2022-04-14:小美有一个长度为n的数组, 为了使得这个数组的和尽量大,她向会魔法的小团进行求助。 小团可以选择数组中至多两个不相交的子数组, 并将区间里的数全都变为原来的10倍。 小团想知道他的魔法最多可以帮助小美将数组的和变大到多少?
1.6K0
2021-08-28:给定一个正数数组arr,长度一定大于6(>=7
2690
2021-04-05:给两个长度分别为M和N的整型数组...
4670
2021-04-07:给定一个非负数组arr,长度为N,那么有N-1种方案可以把arr切成左右两部分
3420
2022-01-20: 矩形区域不超过 K 的最大数值和。 给你一个 m
2470
相关推荐
2021-02-25:给定一个正数数组arr,请把arr中所有的数分成两个集合。
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档