數字子串行和模m最大值問題

2021-10-19 13:05:09 字數 4252 閱讀 1767

問題描述:

給定乙個非負陣列arr,和乙個正數m。

返回arr的所有子串行中累加和 %m 之後的最大值。

如果arr中每個數字不大,怎麼做?

如果arr中 m 的值很小,怎麼做?

如果arr的長度很短,但是arr每個數字比較大並且m比較大呢?

所有子串行的和模上m的值全部求出來,求出最大的即可。

code:

/** 生成每個子串行和的遞迴函式 

* @param arr: 原始陣列名

* @param n: 原始陣列長度

* @param aux_arr: 輔助陣列名,每次求得的子串行和的值放在輔助陣列裡面

* @param index: 等價於二叉樹的層數

* @param k: aux_arr陣列的遍歷位置

* @param sum: 記錄的和

*/int

process

(int

* arr,

int* aux_arr,

int index,

long

& k,

int sum,

int n)

else

}/** 暴力解法 分治問題

* @param arr: 陣列名

* @param n: 陣列長度 n 不能太大,2^32 就已經是uint的極限了

* @param m: 模數

*/int

solution1

(int

* arr,

int n,

int m)

delete

aux_arr;

return maxvalue;

}

這是乙個類揹包問題,dp型別是從左往右的(一共有四種型別)。

同時,這裡有三小問,每一小問的引數取值不同,所以肯定需要採用不同的解法,這就是所謂的看菜吃飯

1)如果arr中每個數字不大,怎麼做?

arr中每個數字不大,那麼陣列和sum就不大,二維dp表可以如下建法:

/** 動態規劃解法(二維dp) 對應第一小問:arr中每個數字不大的情況

* @param arr: 陣列名

* @param n: 陣列長度

* @param m: 模數

*/int

solution2

(int

* arr,

int n,

int m)

// initialize

for(

int i =

0; i < n;

++i)

}for

(int i =

0; i < n;

++i)

dp[0]

[arr[0]

]=true

;for

(int i =

1; i < n;

++i)}}

int ans =0;

// 最後遍歷最後一行就好了

for(

int i =

0; i <= sum;

++i)

// free memory

for(

int i =

0; i < n;

++i)

delete

dp;return ans;

}2)如果arr的sum比較大,而arr中 m 的值很小,怎麼做?

也是建個二維dp表,但是是以m來建, dp[n][m]。

code:

/** 動態規劃解法(二維dp)  對應第二小問:arr中每個數字比較大,而 m 比較小的情況

* @param arr: 陣列名

* @param n: 陣列長度

* @param m: 模數

*/int

solution3

(int

* arr,

int n,

int m)

// initialize

for(

int i =

0; i < n;

++i)

}for

(int i =

0; i < n;

++i)

dp[0]

[arr[0]

% m]

=true

;for

(int i =

1; i < n;

++i)

else}}

int ans =0;

// 最後遍歷最後一行就好了

for(

int i =

0; i < m;

++i)

// free memory

for(

int i =

0; i < n;

++i)

delete

dp;return ans;

}

2)如果arr的sum和m都比較大,而arr的長度比較小,怎麼做?

所以針對上面圖示具體要求,對整個陣列暴力肯定超時,那麼可以將陣列分半,分別去求mod完後的值,然後合併。

具體見code:

// 在arr[index, end]上自由選擇,每一種選擇出來的累加和 mod m 的結果 

// 放到set中去

void

process

(int

* arr,

int index,

int sum,

int end,

int m, std::set<

int>

& s)

}/** 第三小問,如果arr的累加和很大,並且m也很大,構造二維dp表顯然不達要求

* 但是arr的長度不大,意味著暴力解法有希望 (2^n) ,如果 30 < n < 35,

* 那麼整體暴力顯然不行,那麼可以拆成左右兩部分,分別去做,然後合併即可。

*/int

solution4

(int

* arr,

int n,

int m)

tmp--;}

ans = std::

max(ans, num + tmp);}

return ans;

}

四種方法,一起比較測試,如果有一點錯誤,屎都給你測出來了。

具體code:

// for test

void

test()

int m =

rand()

%100+1

;// [1, 100]if(

solution2

(arr, arrlen, m)

!=solution3

(arr, arrlen, m)

|| \

solution1

(arr, arrlen, m)

!=solution2

(arr, arrlen, m)

|| \

solution3

(arr, arrlen, m)

!=solution4

(arr, arrlen, m)

)delete

arr;

} std::cout <<

"test finish. \n\n"

;}

結果:具體問題,具體分析。

紙上得來終覺淺,絕知此事要躬行。

求陣列子串行和最大值

from 輸入一組整數,求出這組數字子串行和中的最大值,只要求出最大子串行的和,不必求出最大值對應的那個序列。序列 2 11 4 13 5 2 5 3 12 9 最大子串行和為21 序列 0 3 6 8 20 21 8 9 10 1 3 6 5 最大子串行和為43 如下 1 include2 usi...

上公升子串行 求和最大值

problem description 乙個只包含非負整數的序列bi,當b1 b2 bs的時候,我們稱這個序列是上公升的。對於給定的乙個序列,我們可以得到一些上公升的子串行,這裡1 i1 i2 ik n。例如 對於序列,有它的一些上公升子串行,如,等等。這些子串行中序列和最大的是子串行,它的所有元素...

求連續子串行的最大值

問題描述 有一串數字 可正可負的int,放在陣列num裡 要求找到起始位置start和終止位置end,使得從start位置到end位置的所有數字之和最大,返回這個最大值max。演算法思想 使用動態規劃。設 f x 為以 a x 終止且包含 a x 的最大序列的和,有 f 1 a 1 f x 1 f ...