【数组基础篇】总结

二分法

  1. 在排序数组中查找元素的第一个和最后一个位置:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/

  2. 搜索插入位置:https://leetcode.cn/problems/search-insert-position/

  3. x 的平方根:https://leetcode.cn/problems/sqrtx/

  4. 完全的有效平方数:https://leetcode.cn/problems/valid-perfect-square/

答案

// 34题
int binarySearch(int* nums, int numsSize, int target, bool lower) {
    int left = 0, right = numsSize - 1, ans = numsSize;
    while (left <= right) {
        int mid = (left + right) / 2;
        if (nums[mid] > target || (lower && nums[mid] >= target)) {
            right = mid - 1;
            ans = mid;
        } else {
            left = mid + 1;
        }
    }
    return ans;
}

int* searchRange(int* nums, int numsSize, int target, int* returnSize) {
    int leftIdx = binarySearch(nums, numsSize, target, true);
    int rightIdx = binarySearch(nums, numsSize, target, false) - 1;
    int* ret = malloc(sizeof(int) * 2);
    *returnSize = 2;
    if (leftIdx <= rightIdx && rightIdx < numsSize && nums[leftIdx] == target && nums[rightIdx] == target) {
        ret[0] = leftIdx, ret[1] = rightIdx;
        return ret;
    }
    ret[0] = -1, ret[1] = -1;
    return ret;
}
// 35题
// 二叉搜索查找目标值索引(优先返回靠前的索引)
int binarySearch(int* nums, int left, int right,int target){
    int index;
    while(left <= right){
        int mid = (left+right)/2;
        if(nums[mid] > target){
            right = mid-1;
            index = mid;
        }
        else if(nums[mid] < target){
            left = mid+1;
        }
        else
            return mid;
    }
    return index;    
}

int searchInsert(int* nums, int numsSize, int target){
    if(nums[numsSize-1] < target)   //由于优先找靠前的,因此这种情况会出错
        return numsSize;

    int index = binarySearch(nums, 0, numsSize-1, target);
    if(nums[index] < target)
        return index+1;
    else
        return index; 
}
// 69题
int mySqrt(int x){
    int max = x;
    int min = 0;
    int t = 1;
    if(x == 1)
        return 1;
    // 此处判断意味着区间缩小为1
    while(max - min > 1){
        t = (max + min)/2;
        // 缩小区间
        if(x/t < t)
            max  = t;
        else
            min = t;
    }
    return min;
}

补充

对于第69题,可以用牛顿二分法做

牛顿二分法:

x n + 1 = x n − f ( x n ) f ′ ( x n ) x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)} xn+1=xnf(xn)f(xn)

f ( x ) = x 2 − n = 0 f(x) = x^2 - n = 0 f(x)=x2n=0 // 其中n是结果

x n + 1 = x n − x n 2 − n 2 x n x_{n+1} = x_n - \frac{{x_n}^2 - n}{2x_n} xn+1=xn2xnxn2n

= 1 2 ( x n + n x n ) = \frac{1}{2}(x_n + \frac{n}{x_n}) =21(xn+xnn)

int y = (x + n/x)/2 迭代到y*y <= x <= (y+1)*(y+1)为止,

代码如下:

int mySqrt(int x){
    if(x == 0)
        return 0;
    int n = x;
    // 防止整数溢出
    int y = (n - x/n ) / 2 + x/n;
    do{
        n = y;
        y = (n + x / n) / 2;
    }while(x/n < n);
    return n;
}
// 367题
bool isPerfectSquare(int num){
    int n = num;
    // 防止整数溢出
    int y = (n - num/n ) / 2 + num/n;
    do{
        n = y;
        y = (n + num / n) / 2;
    }while(num/n < n);
    if(n*n == num)
        return true;
    else
        return false;
}

移除元素

  1. 删除有序数组中的重复项:https://leetcode.cn/problems/remove-duplicates-from-sorted-array/

  2. 移动零:https://leetcode.cn/problems/move-zeroes/

  3. 比较含退格的字符串:https://leetcode.cn/problems/backspace-string-compare/

这个题特别注意它磨灭了我今天刷题的激情

提示:从后往前遍历,先消除,后比较

答案

// 26题
int removeDuplicates(int* nums, int numsSize){
    if(numsSize == 1)
        return 1;
    //从后往前覆盖-双指针
    int length = 0;
    int i = 0,j = 1;
    while(j+1 <= numsSize){
        if(nums[i] != nums[j]){
            nums[++i] = nums[j];
        }
        j++;
    }
    length = ++i;
    return length;
}
// 283题
void moveZeroes(int* nums, int numsSize){
    int j = 0;
    for(int i = 0; i < numsSize; i++)
        if(nums[i] != 0)
            nums[j++] = nums[i];
    for( ;j < numsSize; j++)
        nums[j] = 0;
}
// 844题
bool backspaceCompare(char * s, char * t){
    int i = strlen(s)-1;
    int j = strlen(t)-1;
    int sBack = 0;
    int tBack = 0;
    while(1){
        while(i >= 0){
            if(s[i] == '#')
                sBack++;
            else{
                if(sBack > 0)
                    sBack--;
                else
                    break;
            }
            i--;
        }
        while(j >= 0){
            if(t[j] == '#')
                tBack++;
            else{
                if(tBack > 0)
                    tBack--;
                else
                    break;
            }
            j--;
        }
        // #已消完,比较s[i]和t[j]
        if(i < 0 || j < 0)
            break;
        if(s[i] != t[j])
            return false;
        i--, j--;
    }// while(1)
    if(i == -1 && j == -1)
        return true;
    return false;
}

长度最小的子数组

  1. 水果成篮:https://leetcode.cn/problems/fruit-into-baskets/

答案

// 904题 暴力解(会超时
int totalFruit(int* fruits, int fruitsSize){
    int fruitA = fruits[0];
    int fruitB = fruits[0];
    int total = 0;
    int result = 0;
    int flag = 0;
    int i, j;
    
    for(i = 0; i < fruitsSize; i++){
        fruitA = fruits[i];
        for(j = i; j < fruitsSize; j++){
            // 给fruitB赋值
            if(fruits[j] != fruitA && flag == 0){
                fruitB = fruits[j];
                flag = 1;
            }

            // total自增
            if(fruits[j] == fruitA || fruits[j] == fruitB){
                total++;                
            }
            else
                break;
        }
        // 更新result
        if(result < total){
            result = total;
        }
        total = 0;
        flag = 0;
    }
    return result; 
}

//904题 滑动窗口法
int totalFruit(int* fruits, int fruitsSize){
    int fruitA = fruits[0];
    int fruitB = fruits[0];
    int total = 0;
    int i = 0, j = 0;
    
    while(j < fruitsSize){
        if(fruits[j] == fruitA || fruits[j] == fruitB){
            // 滑动窗口长度的计算!!!
            total = (total > j-i+1) ? total : j-i+1;
            j++;
        }
        else{// 若出现第三种水果
            i = j - 1;  // 更新滑动窗口左端i
            fruitA = fruits[i]; // 更新水果A
            while(i >= 1 && fruits[i-1] == fruitA) //更新i到理想位置
                i--;
            fruitB = fruits[j]; // 更新水果B
            total = (total > j-i+1) ? total : j-i+1;
        }
    }
    return total; 
}
/*
 要抓住循环过程中的变量与不变量
 本题当水果类型固定后,fruitA与fruitB就是不变量,而滑动窗口边界i与j还能变化*/

螺旋数组

剑指offer29:https://leetcode.cn/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/

  1. 螺旋矩阵:https://leetcode.cn/problems/spiral-matrix/

这两个题一样

这个题没答案是因为我放弃了,还有一道困难题也放弃了

  1. 最小覆盖子串:https://leetcode.cn/problems/minimum-window-substring/

本题隶属于长度最小的子数组,那一道题需满足一个条件,推荐的题(水果篮)需要满足两个条件,本题需要满足m个条件。

本文只是节选公众号的中的一篇,我的公众号每日都会更新,欢迎参观
公众号算法每日一更
公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

算法小能手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值