算法习题之子数组达到规定累加和的最大长度系列问题

这篇具有很好参考价值的文章主要介绍了算法习题之子数组达到规定累加和的最大长度系列问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

习题1 给定一个正整数组成的无序数组arr,给定一个正整数值K 找到arr的所有子数组里,哪个子数组的累加和等于K,并且是长度最大的 返回其长度

public static int getMaxLength(int[] arr, int K) {
		if (arr == null || arr.length == 0 || K <= 0) {
			return 0;
		}
		int left = 0;
		int right = 0;
		int sum = arr[0];
		int len = 0;
		while (right < arr.length) {
			if (sum == K) {
				len = Math.max(len, right - left + 1);
				sum -= arr[left++];
			} else if (sum < K) {
				right++;
				if (right == arr.length) {
					break;
				}
				sum += arr[right];
			} else {
				sum -= arr[left++];
			}
		}
		return len;
	}

	// for test
	public static int right(int[] arr, int K) {
		int max = 0;
		for (int i = 0; i < arr.length; i++) {
			for (int j = i; j < arr.length; j++) {
				if (valid(arr, i, j, K)) {
					max = Math.max(max, j - i + 1);
				}
			}
		}
		return max;
	}

	// for test
	public static boolean valid(int[] arr, int L, int R, int K) {
		int sum = 0;
		for (int i = L; i <= R; i++) {
			sum += arr[i];
		}
		return sum == K;
	}

	// for test
	public static int[] generatePositiveArray(int size, int value) {
		int[] ans = new int[size];
		for (int i = 0; i != size; i++) {
			ans[i] = (int) (Math.random() * value) + 1;
		}
		return ans;
	}

	// for test
	public static void printArray(int[] arr) {
		for (int i = 0; i != arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		System.out.println();
	}

	public static void main(String[] args) {
		int len = 50;
		int value = 100;
		int testTime = 500000;
		System.out.println("test begin");
		for (int i = 0; i < testTime; i++) {
			int[] arr = generatePositiveArray(len, value);
			int K = (int) (Math.random() * value) + 1;
			int ans1 = getMaxLength(arr, K);
			int ans2 = right(arr, K);
			if (ans1 != ans2) {
				System.out.println("Oops!");
				printArray(arr);
				System.out.println("K : " + K);
				System.out.println(ans1);
				System.out.println(ans2);
				break;
			}
		}
		System.out.println("test end");
	}

习题2 给定一个整数组成的无序数组arr,值可能正、可能负、可能0 给定一个整数值K 找到arr的所有子数组里,哪个子数组的累加和等于K,并且是长度最大的 返回其长度

public static int maxLength(int[] arr, int k) {
		if (arr == null || arr.length == 0) {
			return 0;
		}
		// key:前缀和
		// value : 0~value这个前缀和是最早出现key这个值的
		HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
		map.put(0, -1); // important
		int len = 0;
		int sum = 0;
		for (int i = 0; i < arr.length; i++) {
			sum += arr[i];
			if (map.containsKey(sum - k)) {
				len = Math.max(i - map.get(sum - k), len);
			}
			if (!map.containsKey(sum)) {
				map.put(sum, i);
			}
		}
		return len;
	}

	// for test
	public static int right(int[] arr, int K) {
		int max = 0;
		for (int i = 0; i < arr.length; i++) {
			for (int j = i; j < arr.length; j++) {
				if (valid(arr, i, j, K)) {
					max = Math.max(max, j - i + 1);
				}
			}
		}
		return max;
	}

	// for test
	public static boolean valid(int[] arr, int L, int R, int K) {
		int sum = 0;
		for (int i = L; i <= R; i++) {
			sum += arr[i];
		}
		return sum == K;
	}

	// for test
	public static int[] generateRandomArray(int size, int value) {
		int[] ans = new int[(int) (Math.random() * size) + 1];
		for (int i = 0; i < ans.length; i++) {
			ans[i] = (int) (Math.random() * value) - (int) (Math.random() * value);
		}
		return ans;
	}

	// for test
	public static void printArray(int[] arr) {
		for (int i = 0; i != arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		System.out.println();
	}

	public static void main(String[] args) {
		int len = 50;
		int value = 100;
		int testTime = 500000;

		System.out.println("test begin");
		for (int i = 0; i < testTime; i++) {
			int[] arr = generateRandomArray(len, value);
			int K = (int) (Math.random() * value) - (int) (Math.random() * value);
			int ans1 = maxLength(arr, K);
			int ans2 = right(arr, K);
			if (ans1 != ans2) {
				System.out.println("Oops!");
				printArray(arr);
				System.out.println("K : " + K);
				System.out.println(ans1);
				System.out.println(ans2);
				break;
			}
		}
		System.out.println("test end");

	}

习题3 给定一个整数组成的无序数组arr,值可能正、可能负、可能0 给定一个整数值K 找到arr的所有子数组里,哪个子数组的累加和<=K,并且是长度最大的 返回其长度

public static int maxLengthAwesome(int[] arr, int k) {
		if (arr == null || arr.length == 0) {
			return 0;
		}
		int[] minSums = new int[arr.length];
		int[] minSumEnds = new int[arr.length];
		minSums[arr.length - 1] = arr[arr.length - 1];
		minSumEnds[arr.length - 1] = arr.length - 1;
		for (int i = arr.length - 2; i >= 0; i--) {
			if (minSums[i + 1] < 0) {
				minSums[i] = arr[i] + minSums[i + 1];
				minSumEnds[i] = minSumEnds[i + 1];
			} else {
				minSums[i] = arr[i];
				minSumEnds[i] = i;
			}
		}
		// 迟迟扩不进来那一块儿的开头位置
		int end = 0;
		int sum = 0;
		int ans = 0;
		for (int i = 0; i < arr.length; i++) {
			// while循环结束之后:
			// 1) 如果以i开头的情况下,累加和<=k的最长子数组是arr[i..end-1],看看这个子数组长度能不能更新res;
			// 2) 如果以i开头的情况下,累加和<=k的最长子数组比arr[i..end-1]短,更新还是不更新res都不会影响最终结果;
			while (end < arr.length && sum + minSums[end] <= k) {
				sum += minSums[end];
				end = minSumEnds[end] + 1;
			}
			ans = Math.max(ans, end - i);
			if (end > i) { // 还有窗口,哪怕窗口没有数字 [i~end) [4,4)
				sum -= arr[i];
			} else { // i == end,  即将 i++, i > end, 此时窗口概念维持不住了,所以end跟着i一起走
				end = i + 1;
			}
		}
		return ans;
	}

	public static int maxLength(int[] arr, int k) {
		int[] h = new int[arr.length + 1];
		int sum = 0;
		h[0] = sum;
		for (int i = 0; i != arr.length; i++) {
			sum += arr[i];
			h[i + 1] = Math.max(sum, h[i]);
		}
		sum = 0;
		int res = 0;
		int pre = 0;
		int len = 0;
		for (int i = 0; i != arr.length; i++) {
			sum += arr[i];
			pre = getLessIndex(h, sum - k);
			len = pre == -1 ? 0 : i - pre + 1;
			res = Math.max(res, len);
		}
		return res;
	}

	public static int getLessIndex(int[] arr, int num) {
		int low = 0;
		int high = arr.length - 1;
		int mid = 0;
		int res = -1;
		while (low <= high) {
			mid = (low + high) / 2;
			if (arr[mid] >= num) {
				res = mid;
				high = mid - 1;
			} else {
				low = mid + 1;
			}
		}
		return res;
	}

	// for test
	public static int[] generateRandomArray(int len, int maxValue) {
		int[] res = new int[len];
		for (int i = 0; i != res.length; i++) {
			res[i] = (int) (Math.random() * maxValue) - (maxValue / 3);
		}
		return res;
	}

	public static void main(String[] args) {
		System.out.println("test begin");
		for (int i = 0; i < 10000000; i++) {
			int[] arr = generateRandomArray(10, 20);
			int k = (int) (Math.random() * 20) - 5;
			if (maxLengthAwesome(arr, k) != maxLength(arr, k)) {
				System.out.println("Oops!");
			}
		}
		System.out.println("test finish");
	}

习题4 给定一个数组arr,给定一个值v 求子数组平均值小于等于v的最长子数组长度

// 暴力解,时间复杂度O(N^3),用于做对数器
	public static int ways1(int[] arr, int v) {
		int ans = 0;
		for (int L = 0; L < arr.length; L++) {
			for (int R = L; R < arr.length; R++) {
				int sum = 0;
				int k = R - L + 1;
				for (int i = L; i <= R; i++) {
					sum += arr[i];
				}
				double avg = (double) sum / (double) k;
				if (avg <= v) {
					ans = Math.max(ans, k);
				}
			}
		}
		return ans;
	}

	// 想实现的解法2,时间复杂度O(N*logN)
	public static int ways2(int[] arr, int v) {
		if (arr == null || arr.length == 0) {
			return 0;
		}
		TreeMap<Integer, Integer> origins = new TreeMap<>();
		int ans = 0;
		int modify = 0;
		for (int i = 0; i < arr.length; i++) {
			int p1 = arr[i] <= v ? 1 : 0;
			int p2 = 0;
			int querry = -arr[i] - modify;
			if (origins.floorKey(querry) != null) {
				p2 = i - origins.get(origins.floorKey(querry)) + 1;
			}
			ans = Math.max(ans, Math.max(p1, p2));
			int curOrigin = -modify - v;
			if (origins.floorKey(curOrigin) == null) {
				origins.put(curOrigin, i);
			}
			modify += arr[i] - v;
		}
		return ans;
	}

	// 想实现的解法3,时间复杂度O(N)
	public static int ways3(int[] arr, int v) {
		if (arr == null || arr.length == 0) {
			return 0;
		}
		for (int i = 0; i < arr.length; i++) {
			arr[i] -= v;
		}
		return maxLengthAwesome(arr, 0);
	}

	// 找到数组中累加和<=k的最长子数组
	public static int maxLengthAwesome(int[] arr, int k) {
		int N = arr.length;
		int[] sums = new int[N];
		int[] ends = new int[N];
		sums[N - 1] = arr[N - 1];
		ends[N - 1] = N - 1;
		for (int i = N - 2; i >= 0; i--) {
			if (sums[i + 1] < 0) {
				sums[i] = arr[i] + sums[i + 1];
				ends[i] = ends[i + 1];
			} else {
				sums[i] = arr[i];
				ends[i] = i;
			}
		}
		int end = 0;
		int sum = 0;
		int res = 0;
		for (int i = 0; i < N; i++) {
			while (end < N && sum + sums[end] <= k) {
				sum += sums[end];
				end = ends[end] + 1;
			}
			res = Math.max(res, end - i);
			if (end > i) {
				sum -= arr[i];
			} else {
				end = i + 1;
			}
		}
		return res;
	}

	// 用于测试
	public static int[] randomArray(int maxLen, int maxValue) {
		int len = (int) (Math.random() * maxLen) + 1;
		int[] ans = new int[len];
		for (int i = 0; i < len; i++) {
			ans[i] = (int) (Math.random() * maxValue);
		}
		return ans;
	}

	// 用于测试
	public static int[] copyArray(int[] arr) {
		int[] ans = new int[arr.length];
		for (int i = 0; i < arr.length; i++) {
			ans[i] = arr[i];
		}
		return ans;
	}

	// 用于测试
	public static void printArray(int[] arr) {
		for (int i = 0; i < arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		System.out.println();
	}

	// 用于测试
	public static void main(String[] args) {
		System.out.println("测试开始");
		int maxLen = 20;
		int maxValue = 100;
		int testTime = 500000;
		for (int i = 0; i < testTime; i++) {
			int[] arr = randomArray(maxLen, maxValue);
			int value = (int) (Math.random() * maxValue);
			int[] arr1 = copyArray(arr);
			int[] arr2 = copyArray(arr);
			int[] arr3 = copyArray(arr);
			int ans1 = ways1(arr1, value);
			int ans2 = ways2(arr2, value);
			int ans3 = ways3(arr3, value);
			if (ans1 != ans2 || ans1 != ans3) {
				System.out.println("测试出错!");
				System.out.print("测试数组:");
				printArray(arr);
				System.out.println("子数组平均值不小于 :" + value);
				System.out.println("方法1得到的最大长度:" + ans1);
				System.out.println("方法2得到的最大长度:" + ans2);
				System.out.println("方法3得到的最大长度:" + ans3);
				System.out.println("=========================");
			}
		}
		System.out.println("测试结束");
	}

总结

题目一主要技巧:利用单调性优化
题目二主要技巧:利用预处理结构优化 + 讨论开头结尾
题目三主要技巧:假设答案法+淘汰可能性文章来源地址https://www.toymoban.com/news/detail-532256.html

到了这里,关于算法习题之子数组达到规定累加和的最大长度系列问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • LeetCode_动态规划_中等_1749.任意子数组和的绝对值的最大值

    给你一个整数数组 nums 。一个子数组 [nums l , nums l+1 , …, nums r-1 , nums r ] 的 和的绝对值 为 abs(nums l + nums l+1 + … + nums r-1 + nums r ) 。请你找出 nums 中和的绝对值 最大的任意子数组(可能为空),并返回该最大值。 abs(x) 定义如下: 如果 x 是负整数,那么 abs(x) = -x 。 如果 x 是非

    2024年02月13日
    浏览(24)
  • 云服务安全不符合规定:云服务的安全措施未达到规定标准

    随着云计算的普及和应用领域的不断拓展,越来越多的企业将业务迁移到云端以降低成本和提高效率. 然而,在享受便利的同时,云安全问题也愈发受到关注。本文将对\\\"云服务安全不符合规定:云服务的安全措施未达到规定标准\\\"问题进行剖析并提出相应解决办法以实现更加安全的

    2024年02月02日
    浏览(37)
  • 加密标准不符合要求:使用的加密技术未达到规定的安全标准

    本文主要讨论了当**加密标准不符合要求时可能会导致的安全风险问题以及可能的解决措施**。加密技术在现代网络安全中扮演着重要角色, 如果不能确保所使用的密码技术和算法符合相关的要求和标准, 那么就会带来极大的安全风险。因此了解并掌握相关的规范和规定至关重

    2024年02月02日
    浏览(51)
  • 动态规划之子数组系列

    1.题目链接:环形⼦数组的最⼤和 2.题目描述:给定一个长度为 n 的环形整数数组 nums ,返回 nums 的非空 子数组 的最大可能和 。 环形数组 意味着数组的末端将会与开头相连呈环状。形式上, nums[i] 的下一个元素是 nums[(i + 1) % n] , nums[i] 的前一个元素是 nums[(i - 1 + n) % n] 。

    2024年02月09日
    浏览(26)
  • 每天一道算法练习题--Day22&& 第一章 --算法专题 --- ----------最大公约数

    关于最大公约数有专门的研究。 而在 LeetCode 中虽然没有直接让你求解最大公约数的题目。但是却有一些间接需要你求解最大公约数的题目。 时间复杂度:最好的情况是执行一次循环体,最坏的情况是循环到 smaller 为 1,因此总的时间复杂度为 O ( N ) O(N) O ( N ) ,其中 N 为 a 和

    2024年02月03日
    浏览(42)
  • 算法刷题Day 23 修剪二叉搜索树+将有序数组转换为二叉搜索树+把二叉搜索树转换为累加树

    递归 好神奇,完全凭感觉写,感觉应该过不了,结果就过了 具体是什么原理可以参考代码随想录的讲解 递归 迭代 使用三个队列来处理(感觉用三个栈也可以) 其实就是以右-中-左的顺序来处理二叉树 每次将当前节点加上上一次访问节点的新值 能想到保存前一次访问节点的

    2024年02月15日
    浏览(30)
  • LeetCode算法题解|​ 669. 修剪二叉搜索树​、108. 将有序数组转换为二叉搜索树、​538. 把二叉搜索树转换为累加树​

    题目链接:669. 修剪二叉搜索树 题目描述: 给你二叉搜索树的根节点  root  ,同时给定最小边界 low  和最大边界  high 。通过修剪二叉搜索树,使得所有节点的值在 [low, high] 中。修剪树  不应该  改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关

    2024年02月06日
    浏览(26)
  • LeetCode每日一题——813. 最大平均值和的分组

    题目: 813. 最大平均值和的分组 难度: 普通 给定数组 nums 和一个整数 k 。我们将给定的数组 nums 分成 最多 k 个相邻的非空子数组 。 分数 由每个子数组内的平均值的总和构成。 注意我们必须使用 nums 数组中的每一个数进行分组,并且分数不一定需要是整数。 返回我们所能

    2024年02月13日
    浏览(32)
  • 累加和最大的组合

    给定一个数组,选择数字组成组合,请问哪个组合的累加和最大。 要求:相邻的数不能同时选。 例子: 定义 dp[i] ,表示在 arr 的 0 ~ i i i 范围上按照选择数组成组合,累加和最大的结果,即所有可能性的最优。 dp[0] 就是在 arr 的 [0,0] 范围上选组合,因为只有一个数,所以

    2024年02月15日
    浏览(20)
  • 将矩阵投影成一维,套用dp解决一维的最大连续子序列和的方法

    速腾聚创各方向算法笔试题公开👨‍💻 春季刷题节活动正在进行中,限量周边/100元京东卡等你哦,和牛牛一起刷真题进大厂!机器人算法工程师、感知算法工程师(AI方向)、感知算法工程师(SLAM方向)h   题解 | #分组过滤练习题# select university, avg(question_cnt) as avg_questio

    2024年04月17日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包