Day Fifteen

算法

来源:力扣(LeetCode)45. 跳跃游戏 II
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。

示例:
输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
说明:
假设你总是可以到达数组的最后一个位置。

解题思路
这是跳跃题的提升版,上次跳跃题是不用具体到最后一个位置,只需要能超过数组长度,就能保证它能到达最后一个位置。现在是让我们找到最小的跳跃步骤到达最后位置,同时它的题目说明总是可以到达数组的最后一个位置,所以就不用判断能不能到达的问题。回到题目,我们一定是从数组0这个位置出发,那么数组0这个位置的值我们设为curmax,当前这个位置能够到达最远的距离。然后依次遍历数组,设置一个变量premax记录在curmax这个范围内的数组,谁的num[i]+i最大,num[i]+i越大,下次能到达的距离就更远。当i>curmax时,即超过数组0位置能到达的最远距离,这时候就是要跳跃了,让跳跃次数加一,然后更新curmax=premax。如果curmax大于等于数组的长度,即可返回记录的跳跃次数。

代码

class Solution {
public:
    int jump(vector<int>& nums) {
        if(nums.size()<2) return 0;
        int curmax=nums[0];
        int premax=nums[0];
        int count=1;
        for(int i=1;i<nums.size();i++){
            if(i>curmax){
                count++;
                curmax=premax;
                if(curmax>=nums.size()){
                    return count;
                }
            }
            if(premax<nums[i]+i){
                premax=nums[i]+i;
            }
        }
        return count;
    }
};

来源:力扣(LeetCode)452. 用最少数量的箭引爆气球
在二维空间中有许多球形的气球。对于每个气球,提供的输入是水平方向上,气球直径的开始和结束坐标。由于它是水平的,所以纵坐标并不重要,因此只要知道开始和结束的横坐标就足够了。开始坐标总是小于结束坐标。
一支弓箭可以沿着 x 轴从不同点完全垂直地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstart,xend, 且满足 xstart ≤ x ≤ xend,则该气球会被引爆。可以射出的弓箭的数量没有限制。 弓箭一旦被射出之后,可以无限地前进。我们想找到使得所有气球全部被引爆,所需的弓箭的最小数量。
给你一个数组 points ,其中 points [i] = [xstart,xend] ,返回引爆所有气球所必须射出的最小弓箭数。

示例 1:
输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:对于该样例,x = 6 可以射爆 [2,8],[1,6] 两个气球,以及 x = 11 射爆另外两个气球

示例 2:
输入:points = [[1,2],[3,4],[5,6],[7,8]]
输出:4

示例 3:
输入:points = [[1,2],[2,3],[3,4],[4,5]]
输出:2

示例 4:
输入:points = [[1,2]]
输出:1

示例 5:
输入:points = [[2,3],[2,3]]
输出:1

提示:
0 <= points.length <= 104
points[i].length == 2
-231 <= xstart < xend <= 231 - 1

解题思路
在这里插入图片描述
我们先将所有的区间范围按左边坐标从小到大排序,即a1<b1<c1<d1<e1<f1;必须得排序!排序的原因最后说。我们可以从图中看出至少需要三名弓箭手,射箭的区域范围分别是[c1,a2],[e1,e2],[f1,f2]。第一个区间范围我们可以看出,区间范围是从[a1,a2]->[b1,a2]->[c1,a2]缩小,也就是当下个区间的最小值大于当前区间的最小值,则范围替换成下个区间的最小值。而最大值则是比谁小,则范围替换成小的那个最大值。当下个区间不再此范围内(即下个区间的最小值大于范围的最大值(由于排序原因)),则更新范围为下个区间的范围,射手加一。反复如此,直至遍历完最后一个范围。
排序原因:利于判断范围,不会漏
例子:[[3,9],[7,12],[3,8],[6,8],[9,10],[2,9],[0,9],[3,9],[0,6],[2,8]]
看到这个用例,我们如果不排序直接判断,得到的结果是错误的。
推导过程:
1.射手数量=1 范围 [3,9]->[7,9]->[7,8] ->[7,8]
2.遍历完前四个后遇到[9,10]不在其范围内,则射手加一,射手数量=2 范围[9,10]->[9,9]->[9,9]->[9,9]->[9,9]
3.再遍历完五个后遇到[0,6]不在其范围内 则射手加一,射手数量=3 范围[0,6]->[2,6]
错误结果为3
正确推到过程我就不推导了:答案:
在这里插入图片描述

代码

class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        if(points.size()<2) return points.size();
        sort(points.begin(),points.end());
        int minShots=1;
        int curmin=points[0][0];
        int curmax=points[0][1];
        for(int i=1;i<points.size();i++){
            if(points[i][0]>curmax){
                curmin=points[i][0];
                curmax=points[i][1];
                minShots++;
            }
            curmin=max(curmin,points[i][0]);
            curmax=min(curmax,points[i][1]);
        }
        return minShots;
    }
};

来源:力扣(LeetCode)871. 最低加油次数
汽车从起点出发驶向目的地,该目的地位于出发位置东面 target 英里处。
沿途有加油站,每个 station[i] 代表一个加油站,它位于出发位置东面 station[i][0] 英里处,并且有 station[i][1] 升汽油。
假设汽车油箱的容量是无限的,其中最初有 startFuel 升燃料。它每行驶 1 英里就会用掉 1 升汽油。
当汽车到达加油站时,它可能停下来加油,将所有汽油从加油站转移到汽车中。
为了到达目的地,汽车所必要的最低加油次数是多少?如果无法到达目的地,则返回 -1 。
注意:如果汽车到达加油站时剩余燃料为 0,它仍然可以在那里加油。如果汽车到达目的地时剩余燃料为 0,仍然认为它已经到达目的地。

示例 1:
输入:target = 1, startFuel = 1, stations = []
输出:0
解释:我们可以在不加油的情况下到达目的地。

示例 2:
输入:target = 100, startFuel = 1, stations = [[10,100]]
输出:-1
解释:我们无法抵达目的地,甚至无法到达第一个加油站。

示例 3:
输入:target = 100, startFuel = 10, stations = [[10,60],[20,30],[30,30],[60,40]]
输出:2
解释:
我们出发时有 10 升燃料。
我们开车来到距起点 10 英里处的加油站,消耗 10 升燃料。将汽油从 0 升加到 60 升。
然后,我们从 10 英里处的加油站开到 60 英里处的加油站(消耗 50 升燃料),
并将汽油从 10 升加到 50 升。然后我们开车抵达目的地。
我们沿途在1两个加油站停靠,所以返回 2 。

解题思路
加油问题,汽车目前油箱油量能走到的最远加油站,途径的加油站的加油量存放在优先队列中,由大到小。当油量不足以走到下一站时,把优先对列中的加油量依次加入,直至足以走到下一站,若是队列为空还是不能到下一站,及证明无法到终点。
代码

class Solution {
public:
    int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) {
        if(stations.size()==0&&startFuel>=target){
            return 0;
        }else if(stations.size()==0&&startFuel<target){
            return -1;
        }
        if(startFuel<stations[0][0]) return -1;
        int curFuel=startFuel;
        vector<int> inista;
        vector<int> finsta;
        priority_queue<int> addMaxFuel;
        int count=0;
        inista.push_back(0);
        inista.push_back(0);
        finsta.push_back(target);
        finsta.push_back(0);
        stations.push_back(finsta);
        stations.insert(stations.begin(),inista);
        for(int i=0;i<stations.size()-1;i++){
            int dis=stations[i+1][0]-stations[i][0];
            while(addMaxFuel.size()>0&&dis>curFuel){
                curFuel+=addMaxFuel.top();
                addMaxFuel.pop();
                count++;
            }
            if(addMaxFuel.size()==0&&dis>curFuel){
                return -1;
            }
            addMaxFuel.push(stations[i+1][1]);
            curFuel-=dis;
        }
        return count;
    }
};

《算法图解》快速排序

除了书本还有结合了网上方法快速排序有两种方法:(来源 《漫画算法:小灰的算法之旅》
一、挖坑法
给定原始数列如下,要求从小到大排序:
在这里插入图片描述

首先,我们选定基准元素Pivot,并记住这个位置index,这个位置相当于一个“坑”。并且设置两个指针left和right,指向数列的最左和最右两个元素:
在这里插入图片描述
接下来,从right指针开始,把指针所指向的元素和基准元素做比较。如果比pivot大,则right指针向左移动;如果比pivot小,则把right所指向的元素填入坑中。
在当前数列中,1<4,所以把1填入基准元素所在位置,也就是坑的位置。这时候,元素1本来所在的位置成为了新的坑。同时,left向右移动一位。
在这里插入图片描述
此时,left左边绿色的区域代表着小于基准元素的区域。
接下来,我们切换到left指针进行比较。如果left指向的元素小于pivot,则left指针向右移动;如果元素大于pivot,则把left指向的元素填入坑中。
在当前数列中,7>4,所以把7填入index的位置。这时候元素7本来的位置成为了新的坑。同时,right向左移动一位。
在这里插入图片描述
此时,right右边橙色的区域代表着大于基准元素的区域。

下面按照刚才的思路继续排序:

8>4,元素位置不变,right左移
在这里插入图片描述
2<4,用2来填坑,left右移,切换到left。
在这里插入图片描述
6>4,用6来填坑,right左移,切换到right。
在这里插入图片描述
3<4,用3来填坑,left右移,切换到left。
在这里插入图片描述
5>4,用5来填坑,right右移。这时候left和right重合在了同一位置。
在这里插入图片描述
这时候,把之前的pivot元素,也就是4放到index的位置。此时数列左边的元素都小于4,数列右边的元素都大于4,这一轮交换终告结束。
在这里插入图片描述

#include<iostream>
using namespace std;
int partition(int* arr, int startIndex, int endIndex) {
    int pivot = arr[startIndex];
    int left = startIndex;
    int right = endIndex;
    // 坑的位置,初始等于pivot的位置
    int index = startIndex;
    //大循环在左右指针重合或者交错时结束
    while ( right >= left ){
    //right指针从右向左进行比较
        while ( right >= left ) {
            if (arr[right] < pivot) {
                arr[left] = arr[right];
                index = right;
                left++;
                break;
            }
            right--;
            }
    //left指针从左向右进行比较
        while ( right >= left ) {
            if (arr[left] > pivot) {
            arr[right] = arr[left];
            index = left;
            right--;
            break;
            }
            left++;
        }
    }
    arr[index] = pivot;
    return index;
}
void quickSort(int* a,int startIndex,int endIndex ){
    if(startIndex>=endIndex){
        return;
    }
    int pivot=partition(a,startIndex,endIndex);
    quickSort(a,startIndex,pivot-1);
    quickSort(a,pivot+1,endIndex);
}
int main(){
    int n=8;
    int arr[8] = {4,7,6,5,3,2,8,1};
    quickSort(arr, 0, n-1);
    for(int i=0;i<n;i++){
        cout<<arr[i]<<endl;
    }
}

二、指针交换法

何谓指针交换法?我们来看一看详细过程。

给定原始数列如下,要求从小到大排序:
在这里插入图片描述
开局和挖坑法相似,我们首先选定基准元素Pivot,并且设置两个指针left和right,指向数列的最左和最右两个元素:
在这里插入图片描述
接下来是第一次循环,从right指针开始,把指针所指向的元素和基准元素做比较。如果大于等于pivot,则指针向左移动;如果小于pivot,则right指针停止移动,切换到left指针。
在当前数列中,1<4,所以right直接停止移动,换到left指针,进行下一步行动。
轮到left指针行动,把指针所指向的元素和基准元素做比较。如果小于等于pivot,则指针向右移动;如果大于pivot,则left指针停止移动。
由于left一开始指向的是基准元素,判断肯定相等,所以left右移一位。
在这里插入图片描述
由于7 > 4,left指针在元素7的位置停下。这时候,我们让left和right指向的元素进行交换。
在这里插入图片描述
接下来,我们进入第二次循环,重新切换到right向左移动。right先移动到8,8>2,继续左移。由于2<8,停止在2的位置。

在这里插入图片描述
切换到left,6>4,停止在6的位置。
在这里插入图片描述
元素6和2交换。
在这里插入图片描述
进入第三次循环,right移动到元素3停止,left移动到元素5停止。

在这里插入图片描述
元素5和3交换。
在这里插入图片描述

进入第四次循环,right移动到元素3停止,这时候请注意,left和right指针已经重合在了一起。

在这里插入图片描述
当left和right指针重合之时,我们让pivot元素和left与right重合点的元素进行交换。此时数列左边的元素都小于4,数列右边的元素都大于4,这一轮交换终告结束。

在这里插入图片描述
代码:

#include<iostream>
using namespace std;
int partition(int* arr, int startIndex, int endIndex) {
    // 取第一个位置的元素作为基准元素
    int pivot = arr[startIndex];
    int left = startIndex;
    int right = endIndex;
    while( left != right) {
        //控制right指针比较并左移
        while(left<right && arr[right] > pivot){
            right--;
        }
        //控制right指针比较并右移
        while( left<right && arr[left] <= pivot) {
            left++;
        }
        //交换left和right指向的元素
        if(left<right) {
            int p = arr[left];
            arr[left] = arr[right];
            arr[right] = p;
        }
    }
    //pivot和指针重合点交换
    int p = arr[left];
    arr[left] = arr[startIndex];
    arr[startIndex] = p;
    return left;
}
void quickSort(int* arr, int startIndex, int endIndex) {
    // 递归结束条件:startIndex大等于endIndex的时候
    if (startIndex >= endIndex) {
        return;
    }
    // 得到基准元素位置
    int pivotIndex = partition(arr, startIndex, endIndex);
    // 根据基准元素,分成两部分递归排序
    quickSort(arr, startIndex, pivotIndex - 1);
    quickSort(arr, pivotIndex + 1, endIndex);
}
int main() {
    int n=8;
    int arr[n] = {4,7,6,5,3,2,8,1};
    quickSort(arr, 0, n-1);
    for(int i=0;i<n;i++){
        cout<<arr[i]<<endl;
    }
}

非递归算法明天再补充!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印度尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深度挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Monster_White

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

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

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

打赏作者

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

抵扣说明:

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

余额充值