leetcode part3 贪心

/**
贪心算法
问题引入:
    有1元、2元、5元、10元、20元、50元、100元
    的钞票无穷多张,现使用这些钞票支付X元
    求问最少需要多少张钞票
贪心法:遵循某种规律,不断贪心的选取当前最优策略的算法设计方法
**/
#include<iostream>
#include<vector>
using namespace std;

int main(){
    int total_money;
    cin>>total_money;

    int a[]={1,2,5,10,20,50,100};
    int num=0;
    while(total_money>0){
        for(unsigned int i=6;i>=0;i--){
            if(a[i]<=total_money){
                num++;
                total_money-=a[i];
                break;
            }
        }
    }
    cout<<"the total num of money is: "<<num<<endl;
    return 0;
}

/**
leetcode  455. 分发饼干
假设你是一位很棒的家长,想要给你的孩子们一些小饼干
但是,每个孩子最多只能给一块饼干
对每个孩子 i ,都有一个胃口值 gi 这是能让孩子们满足胃口的饼干的最小尺寸
并且每块饼干 j ,都有一个尺寸 sj
如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足
你的目标是尽可能满足越多数量的孩子,并输出这个最大数值

注意:
你可以假设胃口值为正
一个小朋友最多只能拥有一块饼干
**/
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(),g.begin()+g.size(),less<int>());
        sort(s.begin(),s.begin()+s.size(),less<int>());
        int content_num=0;
        int p1=0,p2=0;
        // 指针p1和p2分别指向数组g和s

        // 首先尝试让胃口值小的孩子满足,如果胃口值小的孩子
        // 无法被满足,则胃口值大的孩子一定不能被满足

        while(p2<s.size() and p1<g.size()){
            if(s[p2]<g[p1]){
                p2++;
            }
            else{
                // 说明当前的饼干能够满足孩子的胃口值
                p1++;
                p2++;
                content_num++;
            }
        }
        return content_num;
    }
};

int main(){
    vector<int> g1;
    g1.push_back(1);
    g1.push_back(2);
    g1.push_back(3);

    vector<int> s1;
    s1.push_back(1);
    s1.push_back(2);

    Solution s;

    cout<<s.findContentChildren(s1,g1)<<endl;

    return 0;
}

https://www.bilibili.com/video/av29912609/?p=3

/**
leetcode 376. 摆动序列
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列
第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
例如, [1,7,4,9,2,5] 是一个摆动序列,因为差值 (6,-3,5,-7,3) 是正负交替出现的
相反, [1,4,7,2,5] 和 [1,7,4,5,5] 不是摆动序列,
第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
给定一个整数序列,返回作为摆动序列的最长子序列的长度
通过从原始序列中删除一些(也可以不删除)元素来获得子序列
剩下的元素保持其原始顺序。

所要求的的时间复杂度为 O(N)

输入: [1,17,5,10,13,15,10,5,16,8]
输出: 7

使用额外的vector来存储具有最大长度的摇摆子序列

如果输入的vector中仅仅包含一个元素,则它必然是摇摆序列
如果输入的vecto中包含两个元素,
    如果两个元素相等,则摇摆序列的长度为1
    否则无论是升序还是降序,摇摆序列的长度都为2
当vector的长度大于2时
    [1,17,5,10,13,15,10,5,16,8]
    当序列出现连续的递增或者递减时,则只需要一直寻找到单调递增或者单调递减的端点即可

**/
#include<vector>
#include<iostream>
using namespace std;

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        vector<int> result;
        unsigned int i=0;
        bool flag=false;
        while(i<nums.size()){
            if(i==0){
                result.push_back(nums[i]);
                i++;
                continue;
            }

            flag=false;

            while(i<nums.size() and nums[i]==result[result.size()-1]){
                i++;
                flag=true;
            }
            if(flag==true){
                continue;
            }

            if(nums[i]>result[result.size()-1]){
                result.push_back(nums[i]);
                i++;
                while(i<nums.size() and nums[i]>=result[result.size()-1]){
                    result[result.size()-1]=nums[i];
                    i++;
                }
                continue;
            }
            if(nums[i]<result[result.size()-1]){
                result.push_back(nums[i]);
                i++;
                while(i<nums.size() and nums[i]<=result[result.size()-1]){
                    result[result.size()-1]=nums[i];
                    i++;
                }
                continue;
            }
        }
        return result.size();
    }
};

int main(){
    int a[]={1,1};
    vector<int> my;
    for(unsigned int i=0;i<2;i++){
        my.push_back(a[i]);
    }

    Solution s;
    cout<<s.wiggleMaxLength(my)<<endl;
    return 0;
}
/**
leetcode 402. 移掉K位数字
给定一个以字符串表示的非负整数 num
移除这个数中的 k 位数字,使得剩下的数字最小。

假设给定一串固定的字符,则它们所能构成的最小字符串
是将所有的字符进行降序排列

C++ string 模板类删除字符串的方法
string.erase(pos,n)
删除从pos开始的连续n个字符,字符的索引下标从0开始
如果只需要删除一个字符,则n=1

算法:
维护单调栈stack,不断扫描输入的字符串,并根据栈顶元素
判断是否将字符入栈或者将栈顶元素出栈

**/
#include<string>
#include<iostream>
#include<stack>

using namespace std;

class Solution {
public:
    string removeKdigits(string num, int k) {
        if(num.length()==0 or num.length()==k){
            return "0";
        }
        stack<int> helper_stack;
        int index=0;
        while(index<num.length()){
            if(helper_stack.empty()){
                // 如果栈为空,则直接将扫描到的元素入栈
                helper_stack.push(num[index]);
                index++;
            }
            else{
                if(helper_stack.top()<=num[index]){
                    // 如果栈顶元素小于当前扫描到的元素,则说明从高位到低位是升序/非降序存储的
                    // 则直接将扫描到的元素入栈即可
                    helper_stack.push(num[index]);
                    index++;
                }
                else{
                    // 将栈顶元素弹出
                    while(k>0 and !helper_stack.empty() and helper_stack.top()>num[index]){
                        helper_stack.pop();
                        k--;
                    }
                    helper_stack.push(num[index]);
                    index++;
                }
            }
        }

//        cout<<"outside while loop "<<endl;
        // 依次读取栈中的字符,构成的字符串必然是严格非降序排列的
        string result2;
        while(!helper_stack.empty()){
            result2+=helper_stack.top();
            helper_stack.pop();
        }

//        cout<<"result2 this line "<<result2<<"length "<<result2.length()<<endl;

        string result;
        for(int i=result2.length()-1;i>=0;i--){
            result+=result2[i];
            // 将栈中的字符串逆序
//            cout<<"each iteration "<<i<<endl;
        }

//        cout<<"this line "<<result<<endl;

        if(k>0){
        // k大于0,字符串都是降序排列,则从最后一位开始去除
            while(k>0){
                k--;
                result=result.erase(result.length()-1,1);
            }
        }
        // 去除头部的'0'
        while(result[0]=='0'){
//            cout<<"during deleting "<<endl;
//            cout<<result.length()<<"here"<<result<<endl;
            result=result.erase(0,1);
        }
//        cout<<result.length()<<"out "<<result<<endl;
        if(result.length()==0){
            return "0";
        }
        else{
            return result;
        }
    }
};


int main(){
    Solution s;
    cout<<s.removeKdigits("1234567890",9)<<endl;
    return 0;
}
/**
leetcode 55  跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置
数组中的每个元素代表你在该位置可以跳跃的最大长度
判断你是否能够到达最后一个位置。

算法1:
    暴力给出所有可能的情况+剪枝
算法2:
    贪心算法,每次跳跃到的位置应该是走到该位置上之后能够走得最远的位置
**/

#include<vector>
#include<iostream>
using namespace std;

class Solution {
public:
    bool canJump(vector<int>& nums) {
        if(nums.size()<=1){
            return true;
        }
        if(nums[0]==0){
            return false;
        }

        vector<bool> index_avai;
        for(unsigned int i=0;i<nums.size();i++){
            index_avai.push_back(false);
        }
        index_avai[0]=true;

        int index=0;
        int max_valid=1;
        while(index<nums.size()){
            if(index_avai[index_avai.size()-1]==true){
                return true;
            }
            if(index_avai[index]==false){
                index++;
                continue;
            }
            else{
                if(index+nums[index]>=nums.size()){
                    return true;
                }
                for(unsigned int j=max_valid;j<=nums[index]+index;j++){
                    index_avai[j]=true;
                }
                max_valid=nums[index]+index;
                index++;
            }
        }
        return index_avai[index_avai.size()-1];
    }
};

int main(){
    int a[5]={3,2,1,0,4};
    vector<int> a1;
    for(unsigned int i=0;i<5;i++){
        a1.push_back(a[i]);
    }

    Solution s;
    cout<<s.canJump(a1)<<endl;

    return 0;
}
/**
leetcode 55  跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置
数组中的每个元素代表你在该位置可以跳跃的最大长度
判断你是否能够到达最后一个位置。

算法1:
    暴力给出所有可能的情况+剪枝
算法2:
    贪心算法,每次跳跃到的位置应该是走到该位置上之后能够走得最远的位置
**/

#include<vector>
#include<iostream>
using namespace std;

class Solution {
public:
    bool canJump(vector<int>& nums) {
        if(nums.size()<=1){
            return true;
        }
        int index=0;
        int next_index=-1;
        int max_step=-1;
        while(index<nums.size()){
            if(nums[index]==0){
                return false;
            }
            if(index+nums[index]+1>=nums.size()){
                return true;
            }
            for(int i=index+1;i<=index+nums[index];i++){
                if(i+nums[i]>=max_step){
                    max_step=i+nums[i];
                    next_index=i;
                }
            }
            index=next_index;
            // 使用贪心算法找出下一步应该跳跃到的位置
            //cout<<"my here"<<next_index<<endl;

        }
        return false;
    }
};

int main(){
    int a[5]={3,2,1,0,4};
    vector<int> a1;
    for(unsigned int i=0;i<5;i++){
        a1.push_back(a[i]);
    }

    Solution s;
    cout<<s.canJump(a1)<<endl;

    return 0;
}
/**
leetcode 45 跳跃游戏 II

同样是使用贪心算法,尽可能的跳到更远的地方
**/
#include<iostream>
#include<vector>
using namespace std;

class Solution {
public:
    int jump(vector<int>& nums) {
        if(nums.size()<=1){
            return 0;
        }
        int jump_count=0;
        int index=0;

        int max_step=-1;
        int next_index=-1;

        while(index<nums.size()){
            if(nums[index]+index+1>=nums.size()){
                return ++jump_count;
            }
            for(int i=index+1;i<=index+nums[index];i++){
                if(i+nums[i]>=max_step){
                    max_step=i+nums[i];
                    next_index=i;
                }
            }
            index=next_index;
            jump_count++;
        }
        return jump_count;
    }
};

int main(){
    int a[5]={2,3,1,1,4};
    vector<int> a1;
    for(unsigned int i=0;i<5;i++){
        a1.push_back(a[i]);
    }

    Solution s;
    cout<<s.jump(a1)<<endl;

    return 0;
}
/**
leetcode 452. 用最少数量的箭引爆气球

输入:
[[10,16], [2,8], [1,6], [7,12]]

首先根据二维数组每个点的xmin坐标为key对二维数组进行排序

  1       6
    2           8
             7         12  //  由于7>6 ,故而不能被添加到前面的子集合中
                    10       16

right_min  用以记录能够进行合并的所有子区间的最小右端点
并不断更新right_min值
**/

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

bool cmp(vector<int> a,vector<int> b){
    // 重载函数
    if(a[0]<b[0]){
        return true;
    }
    if(a[0]>b[0]){
        return false;
    }
    // a[0]==b[0]
    return a[1]<b[1];
}

class Solution {
public:
    int findMinArrowShots(vector<vector<int> >& points) {
        if(points.size()<=1){
            return points.size();
        }
        sort(points.begin(),points.end());
        int arrow_count=1;
        int index=1;
        int continus_flag=false;

        int right_min=points[0][1];// 记录能够合并的区间的右端点的最小值
//        int right_max=points[0][1];// 记录能够合并的区间的右端点的最大值

        while(index<points.size()){
            while(index<points.size() and points[index][0]<=right_min){
                  // 当当前扫描到的点xmin坐标小于之前区间右端点坐标的最小值时
                  // 则意味着当前点与之前的子集合(包含了所有具有overlap的区间)有overlap
                  // 则可以将当前点添加到子集合中


//                cout<<"右侧区间端点的 "<<"最大值是: "<<right_max<<"   最小值是: "<<right_min<<endl;
//
//                cout<<"index: "<<index<<endl;

                continus_flag=true;
                if(points[index][1]<right_min){
                    right_min=points[index][1];
                }
//                else
//                {
//                    if(points[index][1]>right_max){
//                        right_max=points[index][1];
//                    }
//                }
                index++;
            }

            if(index==points.size()){
                return arrow_count;
            }

            arrow_count++;
            right_min=points[index][1];
//            right_max=points[index][1];

            index++;
            continus_flag=false;

        }
        return arrow_count;
    }
};

int main(){
    int a[][2]={3,9,7,12,3,8,6,8,9,10,2,9,0,9,3,9,0,6,2,8};
    vector<vector<int> > b;
    for(int i=0;i<10;i++){
        vector<int> temp;
        temp.push_back(a[i][0]);
        temp.push_back(a[i][1]);
        b.push_back(temp);
    }

    Solution s;
    cout<<"the total count is: "<<s.findMinArrowShots(b)<<endl;

    sort(b.begin(),b.end());

    for(int j=0;j<10;j++){
        cout<<b[j][0]<<", "<<b[j][1]<<endl;
    }

    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值