力扣算法(每日一题)

书籍:剑指offer,漫画算法(小灰)
怎么刷:限时,一题多解,评论,记录和注释,不会就在题目和答案之间反复横跳,一定要自己写出来,写完思考一下

2023/3/2
二分查找
在这里插入图片描述
二分查找也称折半查找(Binary Search),折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列

首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

关键步骤:设置两个变量来规定头和尾从而来确定中间(二分就是找中间和目标数比较)
而中间数=(right-left)/2+left

class Solution {
    public int search(int[] nums, int target) {
       int n=nums.length-1;
       int left=0;
       int right=n;
       int mid;
       while(right>=left){
           mid=(right-left)/2+left;//不用mid=(right+left)/2是因为怕加法会溢出
           int num=nums[mid];
           if(num==target){
               return mid;
           }else if(num<target){
               left=mid+1;
           }else {
               right=mid-1;
           }
       }
       return -1;
    }
}

例题:
在这里插入图片描述分析:
1.版本数组是有序排列的
2.版本错误和正确是有个界限,就是要找到这个界限

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int left=1;
        int right=n;
        int mid=0;
        while (right>=left) {
            mid=(right-left)/2+left;
            if (isBadVersion(mid)){
                right=mid-1;
            }else{
                left=mid+1;
            }
        }
        return left;
    }
}

在这里插入图片描述

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int flag = 0;
        while (right >= left) {
            int mid = (right - left) / 2 + left;
            if (nums[mid] == target) {
                flag = 1;
                return mid;
            } else if (nums[mid] > target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }

        }
        return left;
    }
}

在这里插入图片描述

public int[] sortedSquares(int[] nums) {
        int[] a=new int[nums.length];//数组的定义
        int t=0;
        for (int i = 0; i <nums.length ; i++) {
            a[i]=nums[i]*nums[i];
        }
        // Arrays.sort(a);
        for (int i = 0; i <a.length ; i++) {
            for (int j = i; j <a.length ; j++) {
                if (a[i]>a[j]){
                    t=a[i];
                    a[i]=a[j];
                    a[j]=t;
                }
            }
        }
        return a;
    }
1、直接插入排序
int* sortedSquares(int* a, int n, int* returnSize){
	*returnSize=n;
	if(n==0) return a;
	a[0]=a[0]*a[0];
	int j;
	for(int i=1;i<n;i++){
		int temp=a[i]*a[i];
		for(j=i-1;j>=0;j--){
			if(temp<a[j]) a[j+1]=a[j];
			else break;
		}
		a[j+1]=temp;
	}
	return a;
}

2、折半插入排序

int* sortedSquares(int* a, int n, int* returnSize){
	*returnSize=n;
	if(n==0) return a;
	a[0]=a[0]*a[0];
	int j;
	for(int i=1;i<n;i++){
		int temp=a[i]*a[i];
		int low=0,high=i-1;
		while(low<=high){
			int mid=(low+high)/2;
			if(temp>a[mid]) low=mid+1;
			else high=mi-1;
		}
		for(j=i-1;j>high;j--){
			a[j+1]=a[j];
		}
		a[j+1]=temp;
	}
	return a;
}

3、选择排序

int* sortedSquares(int* a, int n, int* returnSize){
	*returnSize=n;
	if(n==0) return a;
	int k=0;
	for(int i=0;i<n;i++){
		a[k++]=a[i]*a[i];
	} 
	for(int i=0;i<n-1;i++){
		for(int j=i+1;j<n;j++){
			if(a[j]<a[i]){
				int temp=a[i];
				a[i]=a[j];
				a[j]=temp;
			}
		}
	}
	return a;
}

4、冒泡排序

int* sortedSquares(int* a, int n, int* returnSize){
	*returnSize=n;
	if(n==0) return a;
	int k=0;
	for(int i=0;i<n;i++){
		a[k++]=a[i]*a[i];
	} 
	for(int i=0;i<n;i++){
		for(int j=0;j<n-i-1;j++){
			if(a[j+1]<a[j]){
				int temp=a[j+1];
				a[j+1]=a[j];
				a[j]=temp;
			}
		}
	}
	return a;
}

5、带判断条件的冒泡排序

int* sortedSquares(int* a, int n, int* returnSize){
	*returnSize=n;
	if(n= =0) return a;
	int k=0;
	for(int i=0;i<n;i++){
		a[k++]=a[i]*a[i];
	} 
	int flag=1;
	while(n>1&&flag==1){
		flag=0;
		for(int j=0;j<n-1;j++){
			if(a[j+1]<a[j]){
				flag=1;
				int temp=a[j+1];
				a[j+1]=a[j];
				a[j]=temp;
			}
		}
	}
	return a;
}

6、快排

int Pattion(int *a,int low,int high){
	int temp=a[low],pivoty=a[low];
	while(low<high){
		while(a[high]>=pivoty&&low<high) high--;
		a[low]=a[high];
		while(a[low]<=pivoty&&low<high) low++;
		a[high]=a[low];
	}
	a[low]=temp;
	return low;
}
void QuickSort(int *a,int low,int high){
	int p;
	if(low<high){
		p=Pattion(a,low,high);
		QuickSort(a,low,p-1);
		QuickSort(a,p+1,high);
	}
}

int* sortedSquares(int* a, int n, int* returnSize){
	*returnSize=n;
	if(n==0) return a;
    int k=0;
	for(int i=0;i<n;i++){
		a[k++]=a[i]*a[i];
	}
	QuickSort(a,0,n-1); 
	return a;
}

7、归并排序
可能我写的问题 内存超限了

void MergeSort(int *a,int low,int mid,int high){
	
	int *b=(int *)malloc(sizeof(int)*(high+1));
	for(int i=low;i<=high;i++){
		b[i]=a[i];
	}
	int i=low,j=mid+1,temp=low;
	while(i<=mid&&j<=high){
		if(b[i]<b[j]){
			a[temp++]=b[i++];
		}
		else a[temp++]=b[j++];
	}
	while(i<=mid) a[temp++]=b[i++];
	while(j<=high) a[temp++]=b[j++];
	 
}
void Merge(int *a,int low,int high){
	int mid;
	if(low==high)return ;
	else{
		mid=(low+high)/2;
		Merge(a,low,mid);
		Merge(a,mid+1,high);
		MergeSort(a,low,mid,high);
		
	}
} 
int* sortedSquares(int* a, int n, int* returnSize){
	*returnSize=n;
	if(n==0) return a;
    int k=0;
	for(int i=0;i<n;i++){
		a[k++]=a[i]*a[i];
	}
	Merge(a,0,n-1); 
	return a;
}

8、双指针

int* sortedSquares(int* a, int n, int* returnSize){
	*returnSize=n;
	if(n==0) return a;
	int p=0,q=-1;
	for(int i=0;i<n;i++){
		if(a[i]>=0) {
			p=i;
			q=i-1;
			break;
		}
	} 
	int k=0;
	int *res=(int *)malloc(sizeof(int)*n);
	while(p<n&&q>=0){
		if(a[p]*a[p]<a[q]*a[q]){
			res[k++]=a[p]*a[p];
			p++;
		}
		else{
			res[k++]=a[q]*a[q];
			q--;
		} 
	} 
	while(p<n) {
		res[k++]=a[p]*a[p];
		p++;
	}
	while(q>=0){
		res[k++]=a[q]*a[q];
		q--;
	}
	return res;
}

在这里插入图片描述

  public void rotate(int[] nums, int k) {
   int n = nums.length;
        int[] newArr = new int[n];
        for (int i = 0; i < n; i++) {
            newArr[(i + k) % n] = nums[i];
        }
        System.arraycopy(newArr, 0, nums, 0, n);
    }


在这里插入图片描述方法一:

array在这里是一个指针,而不是数组。使用 malloc 函数动态分配的内存返回的是指向分配内存首地址的指针。
在这个例子中,array是一个指向 int 类型的指针,它指向了一个动态分配的内存块,该内存块大小为 numsSize * sizeof(int) 字节,用于存储整数数据。
虽然我们可以通过 array[i] 这样的方式来访问分配的内存块中的元素,但 array本身仍然是一个指针。用完后要free

calloc函数是C语言中的一个动态内存分配函数之一,它可以动态地分配内存并初始化为0
时间空间复杂度o(n)遍历一次数组,需分配内存空间

int removeDuplicates(int* nums, int numsSize) {

    if(numsSize<=1){
        return numsSize;
    }
    int k=0;
    int *array=(int*)malloc(numsSize*sizeof(int));
    array[0]=nums[0];
    for(int i=1;i<numsSize;++i){
        if(array[k]!=nums[i]){
            k++;
            array[k]=nums[i];
        }
    }
    
    for(int i=0;i<=k;++i){
        nums[i]=array[i];
    }
    free(array);
    return k+1;
}

方法2:
双指针(不是链表什么的才有指针,i,j这些也是指针)时间复杂度on,空间o1

int removeDuplicates(int* nums, int numsSize) {
    if(numsSize<=1) return numsSize;
    int i=0;
    int j=1;
    for(j;j<numsSize;++j){
        if(nums[i]!=nums[j]){
            i++;
            nums[i]=nums[j];
        }
    }
   return i+1;
}

在这里插入图片描述
第一种 暴力解法
遍历数组,第一个元素与target的差是否在后面数组,没有就遍历下一个,两层循环 时间复杂度 on2

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] a=new int[2];
       for(int i=0;i<nums.length;i++){
        for(int j=i+1;j<nums.length;j++){
            if(nums[j]==target-nums[i]){
                a[0]=i;
                a[1]=j;  
            }
        }
       }
       return a;
    }
}

第二种 哈希表(key value)
只需遍历一次,减少时间复杂度,先把第一个元素放进哈希表,然后遍历数组,如果和target之差没有在哈希表里,就把数组存进哈希表里,时间复杂度on

class Solution {
    public int[] twoSum(int[] nums, int target) {

       Map<Integer,Integer> hashtable=new HashMap<>(nums.length-1);
       hashtable.put(nums[0],0);
       for(int i=1;i<nums.length;++i){
        
        if(hashtable.containsKey(target-nums[i])){
            return new int[]{hashtable.get(target-nums[i]),i};
        }
        hashtable.put(nums[i],i);
       }

        return new int[0];
    }
}

在这里插入图片描述方法1:双指针,右指针遍历数组,如果值等于val的话,右指针右移一位,左指针不动,记录这个位置以后是要被代替的
如果右指针不等于val,把右指针的值赋给左指针位置的数组格,左右指针加一

int removeElement(int* nums, int numsSize, int val) {
    int k=0;
    int left=0;
    for(int right=0;right<numsSize;++right){
        if(nums[right]!=val){
        nums[left]=nums[right];
        k++;
        left++;

        }
        
    }
    return k;
}

总结一下:这种原地删数组的,通常用双指针,右指针遍历数组,负责判断元素是否符合要求,符合要删的右指针就右移,不符合的话把右指针的值赋值给左指针,左指针就是负责记录需要被删的位置,等右指针找到不需要删的元素,就把右指针的值赋给左指针,左右指针右移

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值