《LeetCode零基础指南》(第四讲) 一维数组 gyro

1. 解题报告

题干详见:https://blog.csdn.net/WhereIsHeroFrom/article/details/120875955

Q1:33. 搜索旋转排序数组

int search(int* nums, int numsSize, int target){
    /*情形一:如果numsSize为0,即代表数组为空*/
    if(numsSize == 0)
    {
        return -1;
    }


    /*case2:numsSize为1*/
    if(numsSize == 1)
    {
        return nums[0]==target ? 0 : -1;
    }

    /**case 3:numsSize大于1,因为局部有序仍可以使用二分法,只不过是多了一步判断左右那边有序。
    *此种数组中数据旋转后,局部有序,此种结构决定其特性:即数组二分为左右部分后,
    *至少有一部分满足有序性,而另一部分可能无序,针对无序部分,此特性递归有效。
    *二分法套路:
    *(1)定义左右需要变量left,right
    *(2) while (left <= right){}---如果left > right,代表没找到,退出循环
    *(3)“找中点”——int mid = (left + right) / 2;---二分得mid序号
    *(4)“判中点”——if (nums[mid] == target) {}---找到目标循环查找结束,否则确保mid定不是target的序号
    *(5)“判左”——左半部分有序--if (nums[left] <= target && target < nums[mid]){//}
    *(6)“判右”——若右半部分有序--if(numsf[mid] < target && target <= nums[right]){}
    */
    int left = 0;
    int right = numsSize-1;
    while(left<=right)
    {
        int mid = (left + right)/2;

        if(nums[mid] == target)
        {
            return mid;
        }
        /*判哪边有序,"="号不可少*/
        if(nums[left] <= nums[mid])/*左边有序*/
        {
            if(nums[left] <= target && target < nums[mid])
            {
                right = mid - 1;/*缩小范围在左半部分*/
            }
            else
            {
                left = mid + 1;/*舍弃左半部分*/
            }
        }
        else/*右边有序*/
        {
            if(nums[mid] < target && target <= nums[right])
            {
                left = mid + 1;/*缩小范围在右半部分*/
            }
            else
            {
                right = mid - 1;/*舍弃右半部分*/
            }
        }
    }
    return -1;
}

Q2: 81. 搜索旋转排序数组 II

bool search(int* nums, int numsSize, int target){

    /*情形一:如果numsSize为0,即代表数组为空*/
    if(numsSize == 0)
    {
        return false;
    }


    /*case2:numsSize为1*/
    if(numsSize == 1)
    {
        return target == nums[0];
    }

    /**case 3:numsSize大于1,因为局部有序仍可以使用二分法,只不过是多了一步判断左右那边有序。
    *此种数组中数据旋转后,局部有序,此种结构决定其特性:即数组二分为左右部分后,
    *至少有一部分满足有序性,而另一部分可能无序,针对无序部分,此特性递归有效。
    *二分法套路:
    *(1)定义左右需要变量left,right
    *(2) while (left <= right){}---如果left > right,代表没找到,退出循环
    *(3)“找中点”——int mid = (left + right) / 2;---二分得mid序号
    *(4)“判中点”——if (nums[mid] == target) {}---找到目标循环查找结束,否则确保mid定不是target的序号
    *(5)“判左”——左半部分有序--if (nums[left] <= target && target < nums[mid]){//}
    *(6)“判右”——若右半部分有序--if(numsf[mid] < target && target <= nums[right]){}
    */
    int left = 0;
    int right = numsSize-1;
    while(left<=right)
    {
        int mid = (left + right)/2;

        if(nums[mid] == target)
        {
            return true;
        }
        /*判哪边有序,非降序存在---特殊情况
        *使用if - else if-else的绝佳情景
        */
        if(nums[left]==nums[mid]&&nums[mid] == nums[right])
        {
            ++left;
            --right;
        }
        else if(nums[left] <= nums[mid])/*左边有序*/
        {
            if(nums[left] <= target && target < nums[mid])
            {
                right = mid - 1;/*缩小范围在左半部分*/
            }
            else
            {
                left = mid + 1;/*舍弃左半部分*/
            }
        }
        else/*右边有序*/
        {
            if(nums[mid] < target && target <= nums[right])
            {
                left = mid + 1;/*缩小范围在右半部分*/
            }
            else
            {
                right = mid - 1;/*舍弃右半部分*/
            }
        }
    }
    return false;
}

Q3:153. 寻找旋转排序数组中的最小值

/*Q3-method 1.0*/
int findMin(int* nums, int numsSize){
   
   int min = nums[0];


    /*case1:numsSize为1*/
    if(numsSize == 1)
    {
        return nums[0];
    }

    /**case 2:numsSize大于1,因为局部有序仍可以使用二分法,只不过是多了一步判断左右那边有序。
    */
    int left = 0;
    int right = numsSize-1;
    while(left<=right)
    {
        int mid = (left + right)/2;

        /*判哪边有序*/
        if(nums[left] <= nums[mid])/*左边有序*/
        {
            if(nums[left] <= min)
            {
                min = nums[left];
                left = mid + 1;/*缩小范围在左半部分*/
            }
            else /*该else分句不可少*/
            {
                left = mid + 1;
            }
        }
        else/*右边有序,检验完后直接丢弃有序部分*/
        {
            if(nums[mid]  <= min)
            {
                min  = nums[mid];
                right = mid - 1;
            }
            else
            {
                right = mid -1;
            }
        }
    }
    return min;
}



/*Q3_method_2:*/
int findMin(int* nums, int numsSize){
   
    int left = 0;/*隐含数组只有一个值的case*/

    
    int right = numsSize-1;
    while(left < right)/*隐含数组不止一个值得情况*/
    {
        int mid = (left + right)/2;
        /*思路:必须是中间值与最右值比较才能入此简洁,
        *       如果是中间值与最左值比较,则没有如此简洁
        *1)中间值nums[mid]如果小于最右值,则最小值定在中间值序号mid及其以左
        *2)中间值nums[mid]如果大于最右值,根据隐含信息,中间值及其以左舍弃,最小值序号定在中间值以右
        *3)最终结局找到最小值时,left == right,此时跳出while循环
        */

        if(nums[mid] < nums[right])
        {
            right = mid;
            
        }
        else/*右边有序,检验完后直接丢弃有序部分*/
        {
            left = mid + 1;
        }
    }
    return nums[left];
}

Q4:70. 爬楼梯

int climbStairs(int n){

    /*参考题解:我的理解是用了递归思想,回溯,最后一级,要么是一脚踏上来的
    ,要么是两脚;
    每一级台阶都是这么跨上来的,把这种情况累加起来
    f(n) = f(n-1) + f(n-2);符合斐波那契数列*/
    int p =0;
    int q =0;
    int r =1;
    int i;
    for(i = 1;i<=n;++i)
    {
        p = q;
        q = r;
        r = p+q;

    }

 return r;
}

Q5:509. 斐波那契数

/*1)p,q,r构成滚动数组
2)递推关系运用*/
int fib(int n){

    int p=0,q=0;
    int r = 1;
    int i=0;
    if(n==0)
    {
        return 0;
    }
    else if(n==1)
    {
        return 1;
    }
    else{
        for(i=2;i<=n;++i)
        {
            p = q;
            q = r;
            r = p+q;
        }
    }
   return r;
}

Q6:1137. 第 N 个泰波那契数

int tribonacci(int n){
    int p=0,q=0,o=0;/*多了一个数的仿斐波那契数列*/
    int r=1;
    int i;
    if(n == 0)
    {
        return 0;
    }
    else if(n == 1)
    {
        return 1;
    }
    for(i=2;i<=n;++i)
    {
        o = p;
        p = q;
        q = r;
        r = p+q +o;
    }
    return r;

}

Q7:2006. 差的绝对值为 K 的数对数目

int countKDifference(int* nums, int numsSize, int k){
    /*思路:从数组的首元素nums[0]到nums[numsSize-1],考虑差值为负的情况
    *知识点:二维数组循环遍历
    */
    int cnt = 0;
    int i,j;
    for(i=0;i<numsSize - 1;++i)
    {
        for(j = i+1;j<numsSize;++j)
        {
            if(nums[i]-nums[j]==k|| nums[i]-nums[j] ==-k)
            {
                ++cnt;
            }
        }
    }

 return cnt;
}

Q8: LCP 01. 猜数字

/*知识点:指针名代表数组名;用指针形式表达数组*/
int game(int* guess, int guessSize, int* answer, int answerSize){
    int i=0;
    int cnt =0;

    for(i=0;i<guessSize;++i)
    {
        if(*(guess + i) == *(answer + i))
        {
            ++cnt;
        }
    }

    return cnt;

}

Q9:LCP 06. 拿硬币

int minCount(int* coins, int coinsSize){

    /*对每一个数组元素,计算其最少次数cnt,在循环中遍历每个元素i,累加求和sum*/
    int i = 0;
    int sum =0;
    int cnt = 0;
    for(i = 0;i<coinsSize;++i)
    {
        if(coins[i]%2 == 0)
        {
            cnt = coins[i] / 2;
        }
        else
        {
            cnt = (coins[i]+1)/2;
        }
        sum += cnt; 
    }

    return sum;

}

2. 学习报告

(1)初步了解二分法,最关键的是,确定保留有用的部分和舍弃无用的部分。步步为营,不断缩小范围。
(2)了解了斐波那契数列的特点,会用“滚动数组”来求和。
(3)对LeetCode的使用增进了了解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值