Leecode刷题日记Day2(数组、字符串)

初步学习动态规划、KMP算法、贪心算法

贪心算法:通过局部最优解得到全局最优解

动态规划:记日记 + 递归, 以最小情况为底逐步展开

KMP算法:

1.买卖股票的最佳时机 II 

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

示例 1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。
    总利润为 4 + 3 = 7 。

我的思路

求导后,积分所有正的区域

我的算法

int maxProfit(int* prices, int pricesSize) {
    int* diff_prices = malloc(sizeof(int)* (pricesSize-1));
    int profit = 0;
    for(int i  =0; i<pricesSize-1; i++){
        profit += (diff_prices[i] = prices[i+1] - prices[i]) > 0 ?diff_prices[i]:0;
    }
    return profit;
}

算法学习

动态规划,必须学习

2.轮转数组

我的思路

三次反转数组,反转数组这种最基本的算法需要牢记。

我的算法

void swap(int* a, int* b){
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

void reverse(int* nums, int numsSize){
    int start = 0, end = numsSize -1;
    while(start < end){
        swap(&nums[start++], &nums[end--]);
    }
}

void rotate(int* nums, int numsSize, int k) { 
    k %= numsSize;
    reverse(nums, numsSize);
    reverse(nums, k);
    reverse(nums+k, numsSize-k);
}

3. 跳跃游戏 

我的思路

用一个数字来表达能够到达的位置,而不用单独开一个数组来表示。因为这道题的特性,只需要知道最大的地方能不能到达,而不用知道中间的细节

我的算法

bool canJump(int* nums, int numsSize) {
    int max = 0;
    for(int i = 0; i<numsSize-1; i++){
        max = max>nums[i]+ i?max:nums[i]+ i;
        if(max <= i){
            return false;
        }
    }
    return true;
}

4. 跳跃游戏 II

给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:

  • 0 <= j <= nums[i] 
  • i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]

示例 1:

输入: nums = [2,3,1,1,4]
输出: 2

我的思路

第一次自己写动态规划

总结 :

动态规划的递归函数有三种情况:

                             1. 最小情况处理,这里是到达了末尾,返回0.

                             2. 日记本记录直接使用。

                             3. 如果不是前两种情况,计算所有后面能够到达的值,计算方法是递归调用函数计算。并且比较计算出来的值,取最好的结果(最大利润或者最小步数)

我的算法

int count(int* nums, int* diary, int numsSize, int i){ //函数意义:从i出发到n-1的最少跳
    int min = INT_MAX;
    int tmp = 0;
    //如果已经到达了,返回0
    if(i == numsSize-1){
        return 0;
    }
    //如果日记本有记录,直接返回记录
    if(diary[i] != -1){
        return diary[i];
    }
    //没有记录,需要算后面所有位置到n-1的最小跳
    else{
        //比较所有,计算最小值
        for(int j = 1; j<= nums[i] && i+j < numsSize; j++){
            diary[i+j] = count(nums, diary, numsSize, i+j);
            if( diary[i+j] < min){
                min = diary[i+j]+1;
            }
        }
        //算出了最小值,返回min
        return min;
    }
}

int jump(int* nums, int numsSize) {
    int diary[numsSize];
    for(int i = 0; i<numsSize; i++){
        diary[i] = -1;
    }
    return count(nums, diary, numsSize, 0);
}

*算法学习(非常重要,要多复习,理解)

标答使用的是贪心算法,每次选择能够达到的最远处。注意这里最远处能够覆盖其他所有的情况,所以不用考虑其他的,考虑最远的即可。(需要深度思考一下为什么动态规划的题目不能这样做)

#define max(a, b) a>b?a:b
int jump(int* nums, int numsSize) {
    int max = 0, end = 0, step =0;
    for(int i = 0; i<numsSize-1; i++){
        max = max(max, i+nums[i]);
        if(i == end){
            end = max;
            step++;
        }
    }
    return step;
}

5. H 指数

我的思路

我的算法

算法学习

6. 最后一个单词的长度 

我的思路

进单词,单独设置一个循环把这个单词耗尽,出来的时候才进行对last的赋值

注意,单词结束的标志除了空格还有'0'

我的算法

int lengthOfLastWord(char* s) {
    int length = 0, last = 0;
    while(*s != 0){
        if(*s != ' '){
            while(*s != ' ' && *s != 0){
                        length++;
                        s++;
            }
            last = length;
            length = 0;
        }
        else{
            s++;
        }
       
    }
    return last;
}

7. 最长公共前缀 

我的思路

发现有字符串到结尾了或者当前的位置不全一样,就发出退出信号,用lenght同时表达检查的长度和返回的长度。

我的算法

char* longestCommonPrefix(char** strs, int strsSize) {
    int length = 0, cease = 0;
    while(1){
         for(int i =  0; i< strsSize; i++){
            if(strs[0][length] != strs[i][length] || strs[i][length] == 0){
                cease = 1;
                break;
            }
        }
        if(cease){
            break;
        }
        length++;
    }
    strs[0][length] = 0;
    return strs[0];
}

8. 找出字符串中第一个匹配项的下标 

我的思路

我的算法

算法学习

9. 验证回文(双指针)

我的思路

暴力求解

为了方便判别,先对字符串进行预处理,把所有非目标字符换成空格,这件事情可以在确定数组长度的时候做,顺便把大小写给统一了,一举两得。

我的算法

char tolower(char c){
    if(c>='A' && c <= 'Z'){
        c += 'a'-'A';
    }
    return c;
}

int isAor1(char c){
    if(c>='a' && c<='z'){
        return 1;
    }
    else if(c>='0' && c<='9'){
        return 1;
    }
    else{
        return 0;
    }
}

bool isPalindrome(char* s) {
    int length;
    int isP = 1;
    for(length = 0; s[length] != 0; length++){
        s[length] = tolower(s[length]);
        if(!isAor1(s[length])){
            s[length] = ' ';
        }
    }
    int start = 0, end = length-1;
    while(start < end){
        //跳过所有空格,但是注意不要越界
        while(start<=length-1 && !isAor1(s[start])){
            start++;
        }
        while(end>=0&&!isAor1(s[end])){
            end--;
        }

        //当start<end的时候才是有效的判断
        //当start>end的时候说明已经通过检验了!
        if(start<end && s[start] != s[end]){
            isP = 0;
            break;
        }
        start++; end--;
    }
    return isP;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值