leetcode hot100_part17_技巧篇

题目

136.只出现一次的数字

结合题目给的数据特征,使用位运算中的异或^;异或的结果很好记,相互不同就是1,相同就是0;同或一样的

169.多数元素

直接排序了

后面那几个方法不看了,追求效率可以再看,真是小刀拉屁股

75.颜色分类

左神的那个荷兰国旗问题,也牵涉到快排的三路快速排序;简单整理一下荷兰国旗问题;

问题1:数组nums,和一个给定的数x,要求把 <= x的数放在数组左半边,> x的数放在数组的右边;空间复杂度O(1),时间复杂度O(n)

问题2(荷兰国旗问题):数组nums,和一个给定的数x,要求把 <x的数放在数组左半边,=x的数放在数组中间,> x的数放在数组的右边;空间复杂度O(1),时间复杂度O(n)

这两个问题的关键都在于边界的划分;

对于问题1:

  • 定义<=区域的边界 boundary 在index = 0处;区域并不包含边界,小于等于区域为[..., boundary - 1];
  • 指针 i 从数组第一个数开始遍历,遍历完结束
    • 如果nums[i] <= x,nums[i]和小于等于区下一个数(nums[boundary])交换;小于等于区域后移一个位置(boundary++),同时i++;
    • 如果nums[i] > x, i++;

对于问题2:

  • 需要定义两个边界,三个区域
    • 小于区域的边界b1定义为index = 0,大于区的边界b2为index = len -1;
    • [start,b1 -1] ;[b1,b2];[b2 + 1,end]三个区域
  • 指针 i 遍历数组
    • nums[i] < x;nums[i] 和 <区域的下一个数交换(nums[b1]),同时b1++, i++
    • nums[i] = x;i++
    • nums[i] > x;nums[i] 和 >区域的前一个交换(nums[b2]),同时b2-1,i不变(交换到 i 这个位置的数还没判断呢);
  • 当 i 和 >区域撞上,结束;

31.下一个排列

        首先理解题意,全排列?不是,每个排列理解成一个数,题目要求的就是下一个最小的更大的数。因此从左到右递增就是最小的数,递减就是最大的数;

因为要求的是下一个最小的更大的数:

  1. 从后向前遍历,找到第一个能够变大的地方,即递增的地方num[i-1] < num[i];如果整个序列都是递减的,说明这是个最大的数,直接排序返回;
  2. 把num[i-1]换成从 i 位置到结尾这段区间的最小的更大的数,这个数是肯定存在的,至少有个nums[i];
  3. 交换之后把 i 位置到end结尾这段区间的数排序(变为最小),就是结果了。
    1. 之前会有个疑问,第3步为什么只要排序返回就行,万一 i 到 end 是中间大小的一个数,比它大的不还是中间值?返回最小的不就错了;
    2. 其实想想,从第一步开始,没交换之前,i到end就是递减的,说明 i 到 end 之间的是最大数,i-1交换的是i到end之间第一个比i-1大的数,交换后从i到end还是降序的,还是最大值;所以排序得到最小就行了。
    3. 自己之前的方法就是没有想明白这一点,所以才搞什么递归。。

Arrays,sort()排序是降序,然后可以对数组的某些部分进行排序。

287.寻找重复数

一开始的思路是每个数与剩下的数进行异或运算,n方时间复杂度,超时了;写代码的时候报错

bad operand types for binary operator '^';是没注意运算符优先级 if((nums[i] ^ nums[j]) == 0) 异或运算加上括号就行了。

看完下面三个方法看了用时好久

二分法

        首先抓住题目的特性,1~n这n个数放到长度为 n+1的数组里,肯定会有重复的,题目说只有一个重复的,好,这个重复的数就是x了;

        对于1~n这n个数里的每个数i,我们都执行遍历数组的操作,找出数组中小于等于i的元素个数,记为cnt[i];

        结论:对于[1, x -1]里的每个数i,都有cnt[i] <=i;对于[x,n]里的每个数i,cnt[i] > i 的。这个结论也很好证明,当i重复两次,i重复两次以上,这两种情况去想;想不出来去看官方题解。

        好,重点是,我们二分法是在1~n这每个数 i 对应的cnt[i]上进行二分查找,而不是在数组上;二分的标准也不是简单的大于小于某个数,而是看每个数i的情况,cnt[i] ?i 这个大小关系;问题又来了,二分的前提是递增的数组,结合上面的结论,cnt[i]是递增的;不细说了;

        最后,二分查找的写法,是找到第一个cnt[i] > i的元素,结果就是x,这不就是之前总结的模块,一开始还看不懂,真是服了。

二进制

        代码看不懂就去问gpt,对于1~n这n个数,都写成二进制,对于第i个二进制位,计算所有数在第i位上值为1的个数,记为x。对数组nums也进行同样的操作,结果记为y,如果x < y,说明重复的数的二进制第i位为1,为什么,官解写的很细了;

        它的二进制位都知道了还能不知道重复的数

快慢指针

        环形链表的变式,环形链表1是判断有没有换。环形链表2是找到环的入口。这题本质上就是找环的入口

        难的是怎么抽象出环啊,. - 力扣(LeetCode)

        index和num[index]都视节点,index== num[index]视为相同的节点;

        怎么求环入口和正确性,灵山视频:环形链表II【基础算法精讲 07】_哔哩哔哩_bilibili

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值