• 数组累加和问题


    目录

    一、累加和等于num的最长子数组的长度(无负数)

    二、累加和等于num的最长子数组的长度(有负数)

    三、累加和小于等于num的最长子数组的长度


    一、累加和等于num的最长子数组的长度(无负数)

    问题:

            给定一个数组arr, 全是正数; 一个整数K, 求累加和等于K的, 最长子数组。

    思路:

            以使用双指针,一个在左L,一个在右R,形成一个窗口区域。当窗口中的值小于K时,窗口右边界扩大。当窗口中的值大于或等于K时,由于数组中全为正数,所以窗口右边界再扩大,窗口中的值会大于K。所以此时需要窗口左边界右移。当窗口右边界扩大到某个元素,且窗口中的值等于K,计算窗口中此时的长度,与原本系统中的长度作比较,取最大值进行保存。当窗口右边界到达数组最后一个元素,且窗口中的值小于K,直接返回,不做任何操作。最后返回系统中保存得最大长度。

    代码:

    1. public class LongestSumSubArrayLengthInPositiveArray {
    2. public static int getMaxLength(int[] arr, int K) {
    3. if (arr == null || arr.length == 0 || K <= 0) {
    4. return 0;
    5. }
    6. //[L,R]
    7. int L = 0;
    8. int R = 0;
    9. int wsum = arr[0];
    10. int len = 0;
    11. while (R < arr.length) {
    12. if (wsum == K) {
    13. len = Math.max(len, R - L + 1);
    14. wsum -= arr[L++];
    15. } else if (wsum < K) {
    16. R++;
    17. if (R == arr.length) {
    18. break;
    19. }
    20. wsum += arr[R];
    21. } else {
    22. wsum -= arr[L++];
    23. }
    24. }
    25. return len;
    26. }
    27. // for test
    28. public static int right(int[] arr, int K) {
    29. int max = 0;
    30. for (int i = 0; i < arr.length; i++) {
    31. for (int j = i; j < arr.length; j++) {
    32. if (valid(arr, i, j, K)) {
    33. max = Math.max(max, j - i + 1);
    34. }
    35. }
    36. }
    37. return max;
    38. }
    39. // for test
    40. public static boolean valid(int[] arr, int L, int R, int K) {
    41. int sum = 0;
    42. for (int i = L; i <= R; i++) {
    43. sum += arr[i];
    44. }
    45. return sum == K;
    46. }
    47. // for test
    48. public static int[] generatePositiveArray(int size, int value) {
    49. int[] ans = new int[size];
    50. for (int i = 0; i != size; i++) {
    51. ans[i] = (int) (Math.random() * value) + 1;
    52. }
    53. return ans;
    54. }
    55. // for test
    56. public static void printArray(int[] arr) {
    57. for (int i = 0; i != arr.length; i++) {
    58. System.out.print(arr[i] + " ");
    59. }
    60. System.out.println();
    61. }
    62. public static void main(String[] args) {
    63. int len = 50;
    64. int value = 100;
    65. int testTime = 500000;
    66. System.out.println("test begin");
    67. for (int i = 0; i < testTime; i++) {
    68. int[] arr = generatePositiveArray(len, value);
    69. int K = (int) (Math.random() * value) + 1;
    70. int ans1 = getMaxLength(arr, K);
    71. int ans2 = right(arr, K);
    72. if (ans1 != ans2) {
    73. System.out.println("Oops!");
    74. printArray(arr);
    75. System.out.println("K : " + K);
    76. System.out.println(ans1);
    77. System.out.println(ans2);
    78. break;
    79. }
    80. }
    81. System.out.println("test end");
    82. }
    83. }

    二、累加和等于num的最长子数组的长度(有负数)

    问题:

            给定一个数组arr, 一个整数(存在负数)K, 求累加和等于K的, 最长子数组。

    代码:

    1. public class LongestSumSubArrayLength {
    2. public static int maxLength(int[] arr, int k) {
    3. if (arr == null || arr.length == 0) {
    4. return 0;
    5. }
    6. // key:前缀和
    7. // value : 0~value这个前缀和是最早出现key这个值的
    8. HashMap map = new HashMap();
    9. map.put(0, -1); // important
    10. int len = 0;
    11. int sum = 0;
    12. for (int i = 0; i < arr.length; i++) {
    13. sum += arr[i];
    14. if (map.containsKey(sum - k)) {
    15. len = Math.max(i - map.get(sum - k), len);
    16. }
    17. if (!map.containsKey(sum)) {
    18. map.put(sum, i);
    19. }
    20. }
    21. return len;
    22. }
    23. // for test
    24. public static int right(int[] arr, int K) {
    25. int max = 0;
    26. for (int i = 0; i < arr.length; i++) {
    27. for (int j = i; j < arr.length; j++) {
    28. if (valid(arr, i, j, K)) {
    29. max = Math.max(max, j - i + 1);
    30. }
    31. }
    32. }
    33. return max;
    34. }
    35. // for test
    36. public static boolean valid(int[] arr, int L, int R, int K) {
    37. int sum = 0;
    38. for (int i = L; i <= R; i++) {
    39. sum += arr[i];
    40. }
    41. return sum == K;
    42. }
    43. // for test
    44. public static int[] generateRandomArray(int size, int value) {
    45. int[] ans = new int[(int) (Math.random() * size) + 1];
    46. for (int i = 0; i < ans.length; i++) {
    47. ans[i] = (int) (Math.random() * value) - (int) (Math.random() * value);
    48. }
    49. return ans;
    50. }
    51. // for test
    52. public static void printArray(int[] arr) {
    53. for (int i = 0; i != arr.length; i++) {
    54. System.out.print(arr[i] + " ");
    55. }
    56. System.out.println();
    57. }
    58. public static void main(String[] args) {
    59. int len = 50;
    60. int value = 100;
    61. int testTime = 500000;
    62. System.out.println("test begin");
    63. for (int i = 0; i < testTime; i++) {
    64. int[] arr = generateRandomArray(len, value);
    65. int K = (int) (Math.random() * value) - (int) (Math.random() * value);
    66. int ans1 = maxLength(arr, K);
    67. int ans2 = right(arr, K);
    68. if (ans1 != ans2) {
    69. System.out.println("Oops!");
    70. printArray(arr);
    71. System.out.println("K : " + K);
    72. System.out.println(ans1);
    73. System.out.println(ans2);
    74. break;
    75. }
    76. }
    77. System.out.println("test end");
    78. }
    79. }

    三、累加和小于等于num的最长子数组的长度

    题目:

            给定一个数组arr, 值可正, 可负, 可0; 一个整数aim, 求累加和小于等于aim的, 最长子数组, 要求时间复杂度O(N)

    思路:

            设计两个数组minSums和minSumEnds,长度为给定数组的长度。数组元素minSums[i]表示以arr[i]开头,累加和最小的最长子数组的累加和;数组元素minSumEnds[i]与数组元素minSums[i]相对应,表示以arr[i]开头,累加和最小的最长子数组的右边界下标。

            通过反向遍历数组,得到数组minSums和minSumEnds。

    代码:

    1. public class LongestLessSumSubArrayLength {
    2. public static int maxLengthAwesome(int[] arr, int k) {
    3. if (arr == null || arr.length == 0) {
    4. return 0;
    5. }
    6. int N = arr.length;
    7. int[] minSums = new int[N];
    8. int[] minSumEnds = new int[N];
    9. minSums[N - 1] = arr[N - 1];
    10. minSumEnds[N - 1] = N - 1;
    11. for (int i = N - 2; i >= 0; i--) {
    12. if (minSums[i + 1] <= 0) {
    13. minSums[i] = arr[i] + minSums[i + 1];
    14. minSumEnds[i] = minSumEnds[i + 1];
    15. } else {
    16. minSums[i] = arr[i];
    17. minSumEnds[i] = i;
    18. }
    19. }
    20. // 迟迟扩不进来那一块儿的开头位置
    21. //(i...)(...)(...)(end..X) end这一块扩不进来了
    22. int end = 0;
    23. //i.......(sum) end
    24. int sum = 0;
    25. int len = 0;
    26. for (int i = 0; i < N; i++) {
    27. // while循环结束之后:
    28. // 1) 如果以i开头的情况下,累加和<=k的最长子数组是arr[i..end-1],看看这个子数组长度能不能更新res;
    29. // 2) 如果以i开头的情况下,累加和<=k的最长子数组比arr[i..end-1]短,更新还是不更新res都不会影响最终结果;
    30. while (end < N && sum + minSums[end] <= k) {
    31. sum += minSums[end];
    32. end = minSumEnds[end] + 1;
    33. }
    34. len = Math.max(len, end - i);
    35. if (end > i) { // 还有窗口,哪怕窗口没有数字 [i~end) [4,4)
    36. sum -= arr[i];
    37. } else { // i == end, 即将 i++, i > end, 此时窗口概念维持不住了,所以end跟着i一起走
    38. end = i + 1;
    39. }
    40. }
    41. return len;
    42. }
    43. public static int maxLength(int[] arr, int k) {
    44. int[] h = new int[arr.length + 1];
    45. int sum = 0;
    46. h[0] = sum;
    47. for (int i = 0; i != arr.length; i++) {
    48. sum += arr[i];
    49. h[i + 1] = Math.max(sum, h[i]);
    50. }
    51. sum = 0;
    52. int res = 0;
    53. int pre = 0;
    54. int len = 0;
    55. for (int i = 0; i != arr.length; i++) {
    56. sum += arr[i];
    57. pre = getLessIndex(h, sum - k);
    58. len = pre == -1 ? 0 : i - pre + 1;
    59. res = Math.max(res, len);
    60. }
    61. return res;
    62. }
    63. public static int getLessIndex(int[] arr, int num) {
    64. int low = 0;
    65. int high = arr.length - 1;
    66. int mid = 0;
    67. int res = -1;
    68. while (low <= high) {
    69. mid = (low + high) / 2;
    70. if (arr[mid] >= num) {
    71. res = mid;
    72. high = mid - 1;
    73. } else {
    74. low = mid + 1;
    75. }
    76. }
    77. return res;
    78. }
    79. // for test
    80. public static int[] generateRandomArray(int len, int maxValue) {
    81. int[] res = new int[len];
    82. for (int i = 0; i != res.length; i++) {
    83. res[i] = (int) (Math.random() * maxValue) - (maxValue / 3);
    84. }
    85. return res;
    86. }
    87. public static void main(String[] args) {
    88. System.out.println("test begin");
    89. for (int i = 0; i < 10000000; i++) {
    90. int[] arr = generateRandomArray(10, 20);
    91. int k = (int) (Math.random() * 20) - 5;
    92. if (maxLengthAwesome(arr, k) != maxLength(arr, k)) {
    93. System.out.println("Oops!");
    94. }
    95. }
    96. System.out.println("test finish");
    97. }
    98. }

    参考:累加和等于num的最长子数组的长度_GoSantiago的博客-CSDN博客

  • 相关阅读:
    材质、纹理、贴图的区别和关联
    新闻发稿多少钱一篇?轻松发布新闻一站式发稿服务平台
    探讨NLP对行业大量数据信息抽取的技术实现
    彻底搞懂kubernetes调度框架与插件
    Grafana离线安装部署以及插件安装
    泛型擦除的理解
    Linux下yum源配置实战 2
    基于SpringBoot的电影评论网站
    JavaScript -- 03. 运算符介绍
    是时候来点现代c++了 c++11之超级重要之smart pointer详细解析
  • 原文地址:https://blog.csdn.net/z1171127310/article/details/127430442