笔试题思考

在这里插入图片描述
思路:因为不需要考虑先后次序,所以直接枚举1…n/2个一号大礼包 其他都是二号大礼包,枚举过程中更新即可。
在这里插入图片描述
在这里插入图片描述
思路:双指针
从两边开始往中间遍历,遇到‘0’和‘1’则ans++,直到l 和 r相遇。

在这里插入图片描述
思路:重点词汇(只能买一个券+能支持本次所有消费
所以券跟钱用起来其实是一样的:
买券:贪心。买能够买得起且差额最大的券
菜品:01背包

在这里插入图片描述
思路:最大连续子数组和
也就是找个连续数组,在该数组中0的数量-1的数量最大,因此,创建一个临时数组(0->1 1->-1),找子数组+两种元素个数差值最大->最大连续子数组的和(dp),即增加的最多1的个数。
在这里插入图片描述
思路:hash
O(k * n^2)怎么优化?在查找某个数组完美对的时候有没有O(1)的解法?
比如:
5 6 8 10
15 14 12 10
找一个数组内的规律:
第一组[i]-[i-1]得到的值为:{1 2 2}
第二组[i]-[i-1]得到的值为:{-1 -2 -2}
因此,记录下前面{-a -b -c}的个数,即与该数组能构成完美对的个数。
复杂度被优化为:O(k * n)

在这里插入图片描述
暴力:找所有子序列O(2^n)
优化:子序列的和 + 排序->堆
在这里插入图片描述
以下标{0}为根,左边为:{前面不变 最后一个+1} 右子树为{不变 后面加+1}
以上图为例,通过这个规则可以得到数组中所有的子序列。
若先排序为升序的话,则根必然小于两个孩子(兄弟之间大小没有关系)
构造一个pair<int, int> first 存当前的和,second存最大的下标。
左孩子:first-nums[first]+nums[first + 1], first + 1
右孩子:first+nums[first + 1], first + 1
由于兄弟之间大小没有关系,所以不能用队列来做,用小顶堆来做,小顶堆始终first较小的,每次取出堆顶,然后把两个孩子放到堆中,直至取出k个值。
如果找累加和最大的k个,暂时没想到怎么推到所有的子序列。
在这里插入图片描述
与上面的不同的是,这道题里面
有正有负

思路:前k小的累加和(上面)
数组中所有正数的和为sum,然后定义一个临时数组(abs(nums[i])),找出临时数组中的前k小子序列和,然后用sum减去该k个值得到的就是前k个最大的子序列和(sum-原本是正数的相当于没加它, sum-原本是负数的相当于减去它 都能说得通)。
在这里插入图片描述
截止时间的意思是:只要start+10<=该时间,都可以召开,提前按时都可以。
解法:dp(n^2)贪心:排序安排+小根堆维护最小最小收益(nlogn)

先将截止时间由小到大排序,定义一个小根堆(存放已安排的会议得到的收益),变量time记录当前可以开始的时间
遍历升序数组:
如果time + 10<= 截止时间first则安排该会议,将收益second放到堆中,time = first
否则:如果收益大于堆顶的收益,则把堆顶收益pop掉,入second(理由是:如果不能安排该会议,由于该会议的收益大于之前已安排的某场会议的收益,在安排那场会议的时间提前开这场会议收益更多)
在这里插入图片描述
思路:滑动窗口(类似还款)
先用hash记录下s2各个字符出现的个数。定义nums = s2.size(),在s1中一个固定长度的滑动窗口(len=s2.size()),窗口内的元素在hash中-1,如果-1后>=0 则 nums–(有效还款),窗口左端的元素+1,如果+1后>0(有效),则nums++,直到某一个时刻nums==0,此时窗口内的序列为s2的一个排列。
在这里插入图片描述
思路:存在大小的传递性+最多数量->最长递增子序列
下面是一维的思路(排序是关键
step1:排序(宽小到大,高大到小)
step2:高度放到一个数组中,求最长递增子序列的个数,即为ans(同样宽度的,由于高度由大到小所以不是递增,宽度不一样的,满足高度递增就可以了)
在这里插入图片描述
354. 俄罗斯套娃信封问题 https://leetcode.cn/problems/russian-doll-envelopes/
在这里插入图片描述
思路:在具有n个元素的交换环里面的至少n-1次交换
比如:1->2->3->1,至少需要两次交换
在这里插入图片描述
在这里插入图片描述
思路:dfs
step1:子序列+只考虑子序列中元素的个数->只跟str中各个元素的个数有关,跟顺序无关(任意换顺序后得到的字符串的子序列总在原字符串中可以找到)。
step2:在 int len[26]的数组中,每个字符可以选,也可以不选,做dfs。个数为m的字符,可以选的情况为: C m 1 + C m 2 + . . . C m m = 2 m − 1 ( 幂 集 − 空 ) ; 2 m − 1 = ( 1 < < m ) − 1 C_m^1+C_m^2+...C_m^m = 2^m - 1(幂集-空) ; 2^m - 1 = (1 << m) - 1 Cm1+Cm2+...Cmm=2m1;2m1=(1<<m)1
step3:由于dfs时,参数有index,k,所以可以加一个dp[index][k]保存状态
在这里插入图片描述
同理题目:
在这里插入图片描述
子序列+只考虑子序列中的值不考虑子序列内元素的顺序,直接排序->贪心划分
在这里插入图片描述
在这里插入图片描述
俯视图看是个平面,里面有个最大面积a, ans也就是a * 沿着xoy平面切最大的差值
同理,同正视图和侧视图看也是这样。
因此:ans = 三个方向切最大的差值相乘a1a2a3(注意考虑0和10000)。
思路:根据first分组,然后分别排序找最大差值,相乘即为ans
在这里插入图片描述
思路:
step1:先特殊判断,如果数组长度n为奇数/某一个颜色个数超过一半->return -1。
step2:贪心。
比如:[0 4 8][0 6 3]
怎么分配一红一蓝代价最小呢?先求出红所有的代价,4+6=10,然后考虑把哪些变为蓝?减的最多,才能代价最小,因此是减去[1]-[2]最大的值,也就是把第二个变为蓝。4+3=7代价最小。也就是先求出[0]==0的所有元素处[1]的和,然后按照[1]-[2]的差值进行排序,如果需要把m个变为蓝,则将排序后的前m个变为蓝色即可。
在这里插入图片描述
思路:本题是在leetcode135.分发糖果(困难)https://blog.csdn.net/zhangjiaji111/article/details/124237565
的基础上改编来的,leetcode135.只需要两边遍历,两边端点都取1,每个位置取较小值即可。
这道题加了个环怎么做?
比如:3 2 4 5这个环?找到数组中的最小值,把环拆开,即:2 3 5 4 2,两边都放1个糖果,就转换成了leetcode135.的题,最后的ans=accumulate() - 1
在这里插入图片描述
维护一个小顶堆即可。
在这里插入图片描述
思路:排序+离散化+(0-n-1到最终位置的最少次数)
肯定是升序=降序,此时差值绝对值和最小,到底是到升序次数最少还是到降序次数最少?把长度为n的数组各个元素按照元素值离散化映射为0->n-1,不就可以求最少的交换次数了吗?(见上面那道题),分别求出到升序和到降序的次数,然后取较小值即可

离散化代码:
vector<int> v{10, 5, 6, 8, 5, 9};
vector<pair<int, int>> v2;//second记录原位置 
for (int i = 0; i < v.size(); ++i) {
	v2.push_back({v[i], i});
}
sort(v2.begin(), v2.end());
for (int i = 0; i < v2.size(); ++i) {
	v[v2[i].second] = i;
}
//5 0 2 3 1 4

在这里插入图片描述
思路:枚举+最大子数组和模板
重点:子字符串+两种元素差最大->最大子数组和
枚举最多字符和最少字符:外层循环a枚举’a’到’z’,内层循环b枚举’a’到’z’,内内层遍历字符串,a看作是1,b看作是-1,其他字符看作是0,求出的最大子数组和就是ans。
在这里插入图片描述
思路:排序+贪心+dp
step1:先排序
step2:dp[i]表示以i结尾的最大组数。
dp[i] = dp[i - 1], max((dp[i] - dp[i - num + 1]) <= k ? dp[i - num] + 1, 0);
即如果选当前数的话,选前k个总是最好的

连续子数组+子数组内的最小值->dp得到以nums[i]开始/结束的子数组最小值的和
题一:
在这里插入图片描述
对于相等的两个元素,我们规定index较小的值较小
dp[i]表示以i结尾的子数组的最小值的和
转移方程:dp[i]=dp[j]+(i - j)*arr[i], j是左侧第一个小于等于arr[i](因为相等时左边的更小)的下标
若左边不存在比它小的,则dp[j]部分为0。
ans:dp数组的accumulate

题二:
在这里插入图片描述
思路转换
arr[i]贡献:arr[i] * 包括arr[i]的子数组中最小值的和
转化为:arr[i] * (所有子数组的和 - 不包括arr[i]的子数组的最小值的和)
设l[i]表示以arr[i]所有结尾子数组的最小值的和
r[i]表示以arr[i]开始所有子数组最小值的和
则转化为:arr[i]*(sum(l[i]/r[i])-sum(l[0]…l[i-1])-sum(r[i+1]…r[n-1])) 即l和r数组分别用前缀和和后缀和
两个字符串(vector)比较 /hash的count insert时,复杂度O(1)的做法:字符串hash
然而,当hash内的元素过多,查找和插入要再考虑10倍的复杂度即再乘以10

数组/字符串中最短的/最长的子数组->slide windows,见slide windows里面的例题

区间修改 ->差分数组; 单点修改->树状数组

替换:a->b,将数组中所有的a替换为b(可能会修改多个下标)
解决方案:倒着访问operations

3->6 5->6 6->7 也就是:3 5 6 都修改为7,先把6修改为7,产生映射6->7,修改5时,发现6存在映射,此时修改为7,产生5->hash[6]的映射,修改3时,再产生3->hash[5]的映射,把替换数组倒着访问一遍,就能得到数组中每个值要修改的最终值了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值