数组是存放在连续内存空间上的相同类型数据的集合。
数组下标都是从0开始的。
数组内存空间的地址是连续的
大家写二分法经常写乱,主要是因为对区间的定义没有想清楚,区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。
(左闭右闭)
class Solution {
public int search(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
if (target < nums[0] || target > nums[right]){
return -1;
}
while (left <= right){
int mid = (left + right) / 2;
if (target > nums[mid]){
left = mid + 1;
}
if (target < nums[mid]){
right = mid - 1;
}
if(target == nums[mid]){
return mid;
}
}
return -1;
}
}
class Solution {
//二分查找寻找数组的最小值
public int findMin(int[] nums) {
int left = 0;
int right = nums.length - 1;
while(left<right){
int mid = (left + right)/2;
if(nums[mid]>nums[right]){
left = mid + 1;
}else{
right = mid;
}
}
return nums[right];
}
}
class Solution {
public int search(int[] nums, int target) {
//在局部有序中使用二分查找
int len = nums.length;
if(len==0) return -1;
if(len==1) return nums[0]==target?0:-1;
int left = 0;
int right = len - 1;
while(left<=right){
int mid = (left+right)/2;
if(nums[mid] == target){
return mid;
}
if(nums[0]<=nums[mid]){//左边有序
if(nums[0]<=target && nums[mid]>target){//左闭右闭,左区间必须取等
right = mid - 1;
}else{
left = mid + 1;
}
}else{
if(nums[mid]<target && target<=nums[right]){//同理 左闭右闭
left = mid + 1;
}else{
right = mid - 1;
}
}
}
return -1;
}
}
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;
for (int fast = 0; fast < nums.length; fast++){
if(nums[fast] != val){
nums[slow] = nums[fast];
slow += 1;
}
}
return slow;
//双指针遍历到非val的值 slow+1
}
}
相关题目推荐
双指针,慢指针指向新数组的元素,快指针用来遍历。只有当快慢指针不同时,进行元素复制。相同的话就进行指针的移动
class Solution {
public int removeDuplicates(int[] nums) {
if(nums.length == 1){
return 1;
}
int slow = 0;
int fast = 1;
while(fast<nums.length){
if(nums[slow] == nums[fast]){
fast++;
}else{
nums[slow+1] = nums[fast];
slow++;
fast++;
}
}
return slow+1;
}
}
窗口内是什么?
如何移动窗口的起始位置?
如何移动窗口的结束位置?
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int result = Integer.MAX_VALUE;//定义无穷大
int left = 0;
int right = 0;
int sum = 0;
while (right<nums.length){
sum = sum + nums[right];
while (sum>=target){
result = Math.min(result,right-left+1);
sum = sum - nums[left];
left++;
}
right++;
}
if (result==Integer.MAX_VALUE){return 0;}
return result;
}
}
最小滑动窗口
while j < nums.length:
判断[i, j]是否满足条件
while 满足条件:
不断更新结果(注意在while内更新!)
i += 1 (最大程度的压缩i,使得滑窗尽可能的小)
j += 1
最大滑动窗口
while j < nums.length:
判断[i, j]是否满足条件
while 不满足条件:
i += 1 (最保守的压缩i,一旦满足条件了就退出压缩i的过程,使得滑窗尽可能的大)
不断更新结果(注意在while外更新!)
j += 1
区别
最大滑窗是在迭代右移右边界的过程中更新结果,而最小滑窗是在迭代右移左边界的过程中更新结果
class Solution {
//哈希表+最大滑动窗口
public int totalFruit(int[] fruits) {
int left = 0;
int right = 0;//左右边界
int result = 0;//最终结果
int count = 0;//水果类别个数
Map<Integer,Integer> map = new HashMap<>();//哈希表为 水果种类:个数
for (int i=0;i<fruits.length;i++){
map.put(fruits[i],0);
}
while(right<fruits.length){
//1. 判断是否有当前水果(不存在的话类别加1) 其放入果篮当中 更新map
if (map.get(fruits[right])==0){
count++;//没有当前水果,种类要加1
}
map.put(fruits[right],map.get(fruits[right])+1);//放入果篮 key:水果类别,value:在原来的个数基础上加1
// 2. 看当前水果种类是否大于2
while (count>2){
//判断第一种类别的水果个数是否为1(等于1的话 类别减去1) 更新map
if (map.get(fruits[left])==1){
count--;
}
map.put(fruits[left],map.get(fruits[left])-1);
left++;//左边界左移
}
result = Math.max(result,right-left+1);
right++;
}
return result;
}
}
class Solution {
//最小滑窗
public String minWindow(String s, String t) {
if(s.length() == 0 || s == null || t.length() == 0 || t == null){
return "";//特殊情况
}
int left = 0;
int right = 0;
int start = 0;//记录最终结果
int size = Integer.MAX_VALUE;//记录字符串的大小
int count = t.length();//需要的数
int[] need = new int[128];//记录需要的字符个数
for(int i=0;i<t.length();i++){
need[t.charAt(i)]++;
}
while(right<s.length()){
char c = s.charAt(right);//取字符
if(need[c]>0){//需要这个字符
count--;
}
need[c]--;//入窗口
//当count==0,进行处理
if(count == 0){
while(left<right && need[s.charAt(left)]<0){//need元素小于0 说明他不是t所需要的
need[s.charAt(left)]++;
left++;
}
//记录最大值
if(right-left+1<size){
size = right - left + 1;
start = left;
}
//need>=0的情况了
need[s.charAt(left)]++;
left++;
count++;//与前面区别
}
//更新右边界
right++;
}
return size == Integer.MAX_VALUE ? "" : s.substring(start,start+size);
}
}
class Solution {
public int[][] generateMatrix(int n) {
int[][] result = new int[n][n];
int loop = 0;//循环次数
int i,j; //遍历的坐标
int start = 0;//开始坐标 x和y相同
int count = 1;
//1.循环画圈
//边界全部采取左闭右开
while (loop < n/2){
//1.1 从左到右
for (j = start;j < n-loop-1;j++){
result[start][j] = count;
count++;
}
// 1.2 从上到下
for (i = start;i < n - loop-1;i++){
result[i][j] = count;
count++;
}
// 1.3 从右到左
for (;j>loop;j--){
result[i][j] = count;
count++;
}
for(;i>loop;i--){
result[i][j] = count;
count++;
}
start++;
loop++;
}
//2.奇数个中间有点
if (n % 2 == 1){
result[start][start] = count;
}
return result;
}
}