34. 在排序数组中查找元素的第一个和最后一个位置
思路:使用两次二分法,第一次查找target出现的结尾位置,第二次查找target出现的开头位置。
这道题先看第一个二分法,是先通过二分查找target出现的第一个位置:如果mid元素大于等于target,就将范围缩小到mid左边;
第二个二分法查找的是target出现的末尾位置,:如果mid元素小于等于target,就将范围缩小到mid右边;
class Solution {
public int[] searchRange(int[] nums, int target) {
if(nums.length==0) return new int[]{-1,-1};
int l=0,r=nums.length-1,mid=0;
while(l<r){
mid=(l+r)/2;
if(nums[mid]>=target){
r=mid;
}else{
l=mid+1;
}
}
if(nums[l]!=target) return new int[]{-1,-1};
int L=l;
l=0;
r=nums.length-1;
while(l<r){
mid=(l+r+1)/2;
if(nums[mid]<=target){
l=mid;
}else{
r=mid-1;
}
}
return new int[]{L,r};
}
}
这里有两个模板可以参考一下:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = (l + r)/2;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;
}
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = ( l + r + 1 ) /2;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
两个的区别就是mid的计算方式:到底用不用+1:因为如果左边界l更新为l=mid,此时mid的取值就应为mid=(l+r+1)/2。根据代码,当右边界r=l+1时,此时mid=(l+l+1)/2,下取整,mid仍为l,左边界再次更新为l=mid=l,相当于没有变化,while循环就会陷入死循环。
这是因为没有将mid元素单独设置判断条件的原因,如果有if(nums[mid]==target)就不用考虑mid=l的问题,因为l,r只能是mid+1和mid-1,不会等于mid
46. 全排列
改了又改
class Solution {
List<List<Integer>> res=new LinkedList<>();
LinkedList<Integer> path=new LinkedList<>();//这里要注意,path在开始声明时就要是LinkedList
//不然不能使用下面的removeLast方法
boolean[] used;
public List<List<Integer>> permute(int[] nums) {
used=new boolean[nums.length];
if(nums.length==0) return res;
permuteHelper(nums);
return res;
}
public void permuteHelper(int[] nums){
if(path.size()==nums.length){//LinkedList的元素个数只能使用size,不能使用length属性
res.add(new LinkedList<>(path));//这里的意思是,新建一个LinkedList,初始化是path中的元素,且和path顺序一致
//如果直接写成res.add(path),结果不对
return;
}
for(int i=0;i<nums.length;i++){
if(used[i]){
continue;
}
used[i]=true;
path.add(nums[i]);
permuteHelper(nums);
path.removeLast();
used[i]=false;
}
}
}
目前认为,代码中需要res.add(new LinkedList<>(path))的原因是,和多维数组一样,虽然已经有res这个集合,但是集合中各个元素还没有初始化,所以需要先new