java算法day2

news/2024/10/18 14:26:09/
  • 螺旋矩阵
  • 搜索插入位置
  • 查找元素第一个位置和最后一个位置

螺旋矩阵

请添加图片描述
请添加图片描述

解法:模拟,核心在于你怎么转,还有就是处理边界,边界如何收缩,什么时候停止旋转。最内圈的时候怎么处理。

通过上图的模拟来解决这个问题:
1.每条边都采取这种左闭右开来进行统一的处理。
2.分别设置四个边界,left = 0,right = matrix[0].length-1, top = 0,bottom = matrix.length-1。
3.每轮:从左上角开始转一圈,这个转圈就相当于遍历然后把结果加入进结果集。这里建议自己创建一个变量用于遍历,不要用前面预定义的量。每条边处理完就边界往内收缩1。
4.什么时候停:从图中,最内部那里的处理显然就是已经停止转了。这里显然就不是循环的逻辑了,所以到内部这里就该停止。
5.这里就分两种情况,上面图里面画出来了。
第一种:属于长比宽高,这样转最终导致最后需要处理一行,此时上边界和下边界相等,而左边界和右边界不等。
第二种:属于宽比长高,这样转最终导致最后需要处理一列,此时左边界和右边界相等,而上边界和下边界不等。

所以就可以总结出啥时候停止转动,就是当上两种有其中一种情况出现时,就可以停止转了。
while(top<bottom && left<right) 。 一旦有两个边界相等就表示转到最内层了。

这两种情况搞个if else 做判断处理,分别对两种情况进行处理。
第一种情况:由于top==buttom,所以这里可以判断出横坐标为top,纵坐标起点就是left左边界,终点就是right有边界。依次将元素加入结果集

第二种情况:由于left==right,所以这里可以判断列坐标为left。纵坐标起点top上边界,终点就是bottom下边界。依次将元素加入结果集

java">class Solution {public List<Integer> spiralOrder(int[][] matrix) {int top = 0;int bottom = matrix.length-1;int left = 0;int right = matrix[0].length-1;List<Integer> list = new ArrayList<>();while(top<bottom && left<right){for(int i = left;i<right;i++)list.add(matrix[top][i]);for(int i = top;i<bottom;i++)list.add(matrix[i][right]);for(int i = right;i>left;i--)list.add(matrix[bottom][i]);for(int i = bottom;i>top;i--)list.add(matrix[i][left]);++left;--right;++top;--bottom;}if(bottom == top){for(int i = left;i<=right;i++){list.add(matrix[top][i]);}}else if(left == right){for(int i = top;i<=bottom;i++){list.add(matrix[i][top]);}}return list;}
}

搜索插入位置

注意这个题有一个很大的前提:自增不重复。
由于是有序自增不重复,涉及搜索,最快的肯定就是二分查找。所以直接写二分。
写法1:二分,左闭右闭写法。
这种处理,即left = 0。right = nums.length-1。每次处理,两侧都是封闭的区间。
所以while的条件是left<=right。可以取等,因为两侧闭区间,当相遇的时候是有意义的。
从模拟的结果来说
这里还有一个剪枝的优化。nums[mid] == target这个位置可以停,因为当相等的时候,插前面后面都一样。
否则最终插入位置都会在left停止的位置。(自己模拟一下)。

如果左闭右闭,你不进行+1或者-1操作,会发生死循环。看下面这个图的这个例子就懂了

请添加图片描述

快速记忆:二分,左闭右闭,mid剪枝早停,最终left。

请添加图片描述

java">class Solution {public int searchInsert(int[] nums, int target) {int left = 0; //这个就是左闭右的写法,那就是维护的区间初始化就是左右两边。int right = nums.length-1;  //封闭区间while(left<=right){  //由于是封闭区间,所以是有可能左边等于右边的,因为封闭所以他们的格子是有意义的int mid = left + (right-left)/2;   //计算中点if (nums[mid] == target){   return mid;  //技巧剪枝判断早停}else if(nums[mid]>target){right = mid - 1; //这是封闭区间的处理,就是由于那个格子有意义,所以才进行-1.下面的left的处理是同理。}else{left = mid +1 ;}}return left;  //自己模拟,最后就是在left停下}
}

查找元素第一个位置和最后一个位置

解法仍然是二分

**这个题仍然是递增,但是和上一题的区别就在于这个题有重复数字。上一题是没有的。**这个题如果还用上面那个题的思维,那么会出现一个情况,虽然插入后得到的数组看上去没问题,但实际上这个插入位置不一定是题目想要的第一个位置和最后一个位置。看下面这个图。
请添加图片描述
用上一个题的思路二分下来就会有这样的问题,这个指向的位置,不一定是边界。

怎么办:思路:
这里我肯定是想继续往左边找,想办法找到左边界。我们只需改在

target <= nums[mid] 时,让 right = mid - 1即可,这样我们就可以继续在 mid 的左区间继续找 5 。

怎么理解这个操作:
本来是target<nums[mid]。这里变<=。当target<nums[mid]时,就是要往左区间去找目标。而这里取一个等,就是说明这里是有可能有target = nums[mid]的可能性。但是这个mid不一定是最左,所以此时改变右区间的时候,右边界往左边再移动一格(往左边继续搜)。

这里可能有一个问题,万一这个就是左边界怎么办?
继续往后推导,最后left会停在结果的位置。所以不用担心。
直接上推导图。请添加图片描述
请添加图片描述

找上边界就是反过来。逻辑同理,想办法往右边搜,那就是target>=nums[mid],即左边有可能会摸到,但是我还是要往右边挪动一格,那就left = mid + 1.最后right会停在最终的最后一个元素。

现在就直接写两个函数调用就完事了。

java">class Solution {public int[] searchRange(int[] nums, int target) {int left = leftIndex(nums,target);int right = rightIndex(nums,target);// if(nums[left] != target || nums[right] != target){//     return new int[]{-1,-1};// } if(left > right ){return new int[]{-1,-1};}return new int[]{left,right};}public static int leftIndex(int[] nums,int target){int left = 0;int right = nums.length - 1;while(left<=right){int mid = left + (right - left)/2;if(target<=nums[mid]){right = mid -1;}else{left = mid + 1;}}return left;}public static int rightIndex(int[] nums,int target){int left = 0;int right = nums.length - 1;while(left<=right){int mid = left + (right-left)/2;if (target>=nums[mid]){left = mid + 1;}else{right = mid -1;}}return right;}
}

要注意的细节:
1.关于target<=nums[mid]和target>=nums[mid],为什么找左边界要用前者,右边界要用后者。这里用反了就做不出来?
前者:可以发现找左边界的原理是不断的压缩左边维护的区间,所以target<=nums[mid]就可以使得维护的重复右边界往左边收缩。
后者:右边界的原理就是不断的压缩右边维护的区间,所以target<=nums[mid]就可以使得维护的重复左边界往左边收缩。

2.特判

java">// if(nums[left] != target || nums[right] != target){//     return new int[]{-1,-1};// } 

这里千万不能这么写。必须这样写:

java">if(left > right ){return new int[]{-1,-1};}

这个例子用于判断当target不在数组中。
先说结果:
当leftIndex执行结束后,left变量指向的是第一个大于target元素的位置,或者是数组长度(如果target大于所有元素)。
当rightIndex指向结束后,right指向的是最后一个小于target的元素的位置,或者是-1(如果target小于所有元素)

看模拟就懂了
nums = [5, 7, 7, 8, 8, 10],目标值 target = 6。
执行 leftIndex:
初始:left = 0, right = 5
第一次循环:mid = 2 (nums[2] = 7), 7 > 6 -> right = 1
第二次循环:mid = 0 (nums[0] = 5), 5 < 6 -> left = 1
第三次循环:mid = 1 (nums[1] = 7), 7 > 6 -> right = 0
循环结束:left = 1
可以看出最后left停留在第一个大于target元素的位置。

执行 rightIndex:
初始:left = 0, right = 5
第一次循环:mid = 2 (nums[2] = 7), 7 > 6 -> right = 1
第二次循环:mid = 0 (nums[0] = 5), 5 < 6 -> left = 1
第三次循环:mid = 1 (nums[1] = 7), 7 > 6 -> right = 0
循环结束:right = 0
可以看出最后left停留在第一个小于target元素的位置。

综上,在这个例子中,最后那肯定left>right了。

3.有可能会想到这个例子nums = []。
这个也包含在里面处理了,这样一开始就left>right了。最终left = 0,right = -1.所以也满足left>right.


http://www.ppmy.cn/news/1428460.html

相关文章

数据赋能(58)——要求:数据赋能实施部门能力

“要求&#xff1a;数据赋能实施部门能力”是作为标准的参考内容编写的。 在实施数据赋能中&#xff0c;数据赋能实施部门的能力体现在多个方面&#xff0c;关键能力如下图所示。 在实施数据赋能的过程中&#xff0c;数据赋能实施部门应具备的关键能力如下。 理性思维与逻辑分…

海尔推行TPM管理的经验分享:打造高效制造新标杆

海尔集团&#xff0c;作为家电行业的佼佼者&#xff0c;其推行TPM&#xff08;全面生产维护&#xff09;管理的成功经验&#xff0c;无疑为众多寻求管理突破的企业提供了宝贵的借鉴。 一、TPM管理的核心理念 TPM&#xff08;Total Productive Maintenance&#xff09;即全面生…

flask 请求对象

客户端网页的数据作为全局请求对象发送到服务器。要处理请求数据&#xff0c;请求对象应该从Flask模块导入。 form 是包含表单参数及其值的键值对的字典对象。 args 解析问号(?)后的 url 部分查询字符串的内容。 cookies 保存 cookie 名称和值的字典对象。 file 与上传文件有关…

Linux配置路由服务器

# 中转服务器添加路由规则 route add -net 0.0.0.0/0 gw 192.168.61.2 #0.0.0.0/0表示所有网段所有ip地址&#xff0c;192.168.61.2是nat网卡的ip如果想让其他主机上网&#xff0c;需要在2主机配置NAT规则&#xff0c;将其他主机的网关ip指向02主机 02主机设置NAT转换 iptable…

双向链表的实现(详解)

目录 前言初始化双向链表的结构为双向链表的节点开辟空间头插尾插打印链表尾删头删查找指定位置之后的插入删除pos节点销毁双向链表 前言 链表的分类&#xff1a; 带头 不带头 单向 双向 循环 不循环 一共有 (2 * 2 * 2) 种链表 带头指的是&#xff1a;带有哨兵位节点 哨兵位&a…

paho-mqtt 库揭秘

文章目录 **paho-mqtt 库揭秘**第一部分&#xff1a;背景介绍第二部分&#xff1a;paho-mqtt 是什么&#xff1f;第三部分&#xff1a;如何安装这个库&#xff1f;第四部分&#xff1a;库函数使用方法第五部分&#xff1a;场景应用第六部分&#xff1a;常见Bug及解决方案第七部…

存储过程的查询

Oracle从入门到总裁:​​​​​​https://blog.csdn.net/weixin_67859959/article/details/135209645 在实际使用中&#xff0c;经常会需要查询数据库中已有的存储过程或者某一个存储过程的内容&#xff0c; 下面就介绍-下如何查询存储过程。 这需要使用到数据字典 user_sou…

ROS机器人实战,对标古月老师HRMRP机器人(一)——机器人总体方案设计

咳咳&#xff01;这个是自己的毕业设计&#xff0c;内容比较多就拆开发。设计实现了一款SLAM移动机器人&#xff0c;加机械臂完成视觉识别抓取的&#xff0c;同时还有语音识别控制、QT上位机控制、Web网页控制。前几年看古月老师的视频&#xff0c;看到古月老师设计的HRMRP&…