map 容器的用法
map 根据 value 排序:借助vector实现
1 |
|
去重
1 | if(it.second!=num){ |
string里的四个 find 函数
- find_first_of():正向查找在原字符串中第一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置。若查找失败,则返回npos。
- find_last_of():逆向查找在原字符串中最后一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置。若查找失败,则返回npos。
- find_first_not_of():正向查找在原字符串中第一个与指定字符串(或字符)中的任一字符都不匹配的字符,返回它的位置。若查找失败,则返回npos。
- find_last_not_of():正向查找在原字符串中最后一个与指定字符串(或字符)中的任一字符都不匹配的字符,返回它的位置。若查找失败,则返回npos。
普通stirng.find函数查找返回第一个的位置,查不到返回npos(-1)。
1 | class cmp1 { |
1 | class Solution { |
更简单的版本
1 | class Solution { |
记忆化搜索例题
AcWing 901. 滑雪
1 |
|
Problem: 100220. 相同分数的最大操作数目 II
暴力dfs:
1 |
|
520 / 549 个通过的测试用例
借助deque的暴力dfs
1 |
|
AC
二分
1 |
|
计算
mid时需要防止溢出,代码中left + (right - left) / 2就和(left + right) / 2的结果相同,但是有效防止了left和right太大,直接相加导致溢出的情况。为什么 while 循环的条件中是 <=,而不是 <
while(l<r): 初始化r的值r = nums.size相当于左闭右开,[left,right),right 不能取到初始值while(l<=r): 初始化r的值r = nums.size -1相当于左闭右闭,[left,right],right 可以取到初始的最大值。停止搜索的区间?
找到了目标值的时候可以终止:
1
2if(nums[mid] == target)
return mid;但如果没找到,就需要 while 循环终止,然后返回 -1。那 while 循环什么时候应该终止?
==搜索区间为空的时候应该终止==,意味着你没得找了,就等于没找到嘛。
while(left <= right)的终止条件是left == right + 1,写成区间的形式就是[right + 1, right],或者带个具体的数字进去[3, 2],可见这时候区间为空。所以这时候 while 循环终止是正确的,直接返回 -1 即可。while(left < right)的终止条件是left == right,写成区间的形式就是[right, right],或者带个具体的数字进去[2, 2],这时候区间非空,还有一个数 2,但此时 while 循环终止了。也就是说区间[2, 2]被漏掉了,索引 2 没有被搜索,如果这时候直接返回 -1 就是错误的。
当然,如果你非要用
while(left < right)也可以,我们已经知道了出错的原因,就打个补丁好了:1
2
3
4
5
6//...
while(left < right) {
// ...
}
return nums[left] == target ? left : -1;//判断漏掉的那个数是不是符合目标值
为什么
left = mid + 1,right = mid - 1?我看有的代码是right = mid或者left = mid,没有这些加加减减,到底怎么回事,怎么判断?答:这也是二分查找的一个难点,不过只要你能理解前面的内容,就能够很容易判断。
刚才明确了「搜索区间」这个概念:
如果搜索区间是两端都闭的,即
[left, right]。那么当我们发现索引mid不是要找的target时,下一步当然去搜索区间[left, mid-1]或者区间[mid+1, right], 因为mid已经搜索过,应该从搜索区间中去除。如果搜索区间左闭右开,即
[left, right],则可以搜索区间[mid+1,right)和[left,mid)。因为右边界不会被搜索到。关注点在于 mid 作为左右边界时的变化,即是否有必要+1 -1 。
为什么求右侧边界最后返回
left - 1而不像左侧边界的函数,返回left?而且我觉得这里既然是搜索右侧边界,应该返回right才对。答:首先,while 循环的终止条件是
left == right,所以left和right是一样的。至于 left 是否要减1,关键在于
if (nums[mid] == target)语句,1
2
3
4// 增大 left,锁定右侧边界
if (nums[mid] == target) {
left = mid + 1;
// 这样想: mid = left - 1因为我们对 left 的更新必须是 left = mid + 1,就是说 while 循环结束时,nums[left] 一定不等于 target 了,而 nums[left-1] 可能是 target。
至于为什么 left 的更新必须是 left = mid + 1,当然是为了把 nums[mid] 排除出搜索区间,这里就不再赘述
左闭右闭的时候:循环结束条件相比左闭右开的
left == right变成了left == right +1,即left-1 == right。求右侧边界的函数条件里,仍然是
left = mid + 1。所以结果left - 1求左侧边界的函数条件,是
right = mid - 1,将 right 转换为 left ,右:left - 1 = mid -1,即left = mid。所以结果是
left
由上可知,结果取left还是right,其实根据循环条件结束的判断来看,两者可以互相换算,是一样的。
取left后是否要 - 1,要看
nums[mid]==target判断语句的内容,是 left 还是 right。(实际上就是看左闭右开还是左闭右闭,也就是<还是<=。