题目杂记(二)

题目杂记(二)

题目1

题目

给定一个有序数组arr,从左到右依次表示X轴上从左往右点的位置。给定一个正整数K,返回如果有一根长度为K的绳子,最多能盖住几个点?绳子的边缘点碰到X轴上的点,也算盖住

题目2

在这里插入图片描述

题目3

题目

在这里插入图片描述

题目4

题目

长度为N的数组arr,一定可以组成N^2个数值对。
例如arr = [3,1,2],
数值对有(3,3) (3,1) (3,2) (1,3) (1,1) (1,2) (2,3) (2,1) (2,2),
也就是任意两个数都有数值对,而且自己和自己也算数值对。
数值对怎么排序?规定,第一维数据从小到大,第一维数据一样的,第二维数组也从小到大。所以上面的数值对排序的结果为:
(1,1)(1,2)(1,3)(2,1)(2,2)(2,3)(3,1)(3,2)(3,3)

给定一个数组arr,和整数k,返回第k小的数值对。

思路

暴力的做法是,先做一遍组合,得到所有的数值对(N^ 2个),然后将组合之后的数值对排序,然后遍历一遍,选出最大的。时间复杂度是O(N^2logN ^2)。
注意到每个数据都可以和其他元素以及自身做组合,产生N个组合键值对。要找第K小的键值对,可以先找其第一个元素,也就是先将原始数组arr排序,然后,找到其中第(k-1)/N个数,就是要找的键值对的第一个元素。这很好理解,举个例子:
arr = [1,2,2,3,3,3,4,5,6,7],共十个元素,要找做完组合之后的第45个元素,那么1开头的键值对是10个,肯定排在最前面;2开头的键值对20个,肯定排在1开头的之后;3开头的键值对30个,这其中就包含要找的键值对。因此 (45-1)/10 = 4,索引为4的位置的元素3,就是要找的键值对的第一个元素。
接下来找第二个元素,由于原始数组arr中可能存在重复值,所以相对来说有点复杂。还是以上面的例子说明,要找第45个元素,其实就是找以3开头的键值对中第15个元素,因为1开头的和2开头已经去掉了30个。由于由3个3,那么在具体组合的时候,就会有 (3,1)(3,1)(3,1)(3,2)(3,2)(3,2)(3,2)…,因此,以3开头的第15个键值对的第二个元素,就是(15-1)/3 = 4的位置。
将两个元素组合起来,就是最终的答案。时间复杂度是O(NlogN),也就是前期的排序的时间,后面都是O(N)的操作。

代码

	public static class Pair {
		public int x;
		public int y;

		Pair(int x, int y) {
			this.x = x;
			this.y = y;
		}
	}

	// O(N*logN)的复杂度,你肯定过了
	public static int[] kthMinPair2(int[] arr, int k) {
		int N = arr.length;
		if (k > N * N) {
			return null;
		}
		// O(N*logN)
		Arrays.sort(arr);	
		// 第K小的数值对,第一维数字,是什么   是arr中
		int fristNum = arr[(k - 1) / N];
		int lessFristNumSize = 0;// 数出比fristNum小的数有几个
		int fristNumSize = 0; // 数出==fristNum的数有几个
		// <= fristNum
		for (int i = 0; i < N && arr[i] <= fristNum; i++) {
			if (arr[i] < fristNum) {
				lessFristNumSize++;
			} else {
				fristNumSize++;
			}
		}
		int rest = k - (lessFristNumSize * N);
		return new int[] { fristNum, arr[(rest - 1) / fristNumSize] };
	}

题目5

题目

在这里插入图片描述

题目5

题目

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

示例1:

输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

思路

可以用动态规划做,用f[i]表示以i结尾的子数组和的最大值,转移方程是f[i] = max(f[i-1]+v[i],v[i]),时间复杂度是O(N),空间复杂度也是O(N)

更好的方式是时间复杂度O(N),空间复杂度O(1),思路如下:定义一个变量curr,一个变量max。
cur每次迭代都累加num[i],max = max(max,cur),如果cur<0,那么cur重置为0。
思路很简单,那么为什么可行呢。假设存在一个子数组[j,…,k],这个和最大,当然这个子数组可能不唯一,但这不影响。如果上面这个思路,可以完整捕捉到这个数组,那么就说明思路是正确的。

设[…i,j,…,k,m],那么当遍历到i时,cur一定是小于0的,不然的话,[j,…,k]就不是和最大的子数据了。那么,cur在遍历到j时,就会重置为0,开始捕获j。并且,遍历到j到k中间任何一个数据时,cur都不会小于0,不然的话,假设[j,…l]小于0,[j,…,k]的和是子数组最大,那么[l,…k]的和应该更大,这是矛盾的。所以,算法可以完整捕捉到[j,…,k]这个最大的子数组。
这个算法就是正确的

代码

    public int maxSubArray(int[] nums) {
        int n = nums.length;
        int cur = 0;
        int max = Integer.MIN_VALUE;
        for(int i=0;i<n;i++){
            cur = cur+ nums[i];
            max = Math.max(max,cur);
            if(cur<0){
                cur = 0;
            }
        }
        return max;
    }

题目6

题目

在这里插入图片描述

思路

如果采用暴力的思路,时间复杂度是O(N^6)的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值