7-70 跳一跳 (升级版)分数 100(bfs做法)

作者 Drizzle

单位 山东科技大学

我跳累了~😢

人活着本没有意义,但只有活着就会碰到很多有趣的事,就像你发现了花,而我发现了你一样。


这里有一段整数数组nums,你一开始处于下标为0的第一个元素处,请求出你最少跳几次能到达数组的末尾位置。

当你在i位置时可以跳跃到一下三个位置:

  • i + 1:i+1 < nums.length
  • i - 1:i-1 >= 0
  • j:nums[i] == nums[j]

输入:

第一行输入n表示nums的长度
第二行以空格分隔输入nums的每个元素

11
11 22 7 7 7 7 7 7 7 22 13

输出:

输出一行最小跳跃次数

3

范围:

  • 1 <= nums.length <= 5 * 104
  • -108<= nums[i] <= 108

样例解释:

 

其实我觉得题面解释蛮清楚滴!但是有人可能还有点疑惑。 总共有1个数组,11个数。 你可以把这11个数看成有编号的11个格子, 第1 个格子的下标是0, 格子的值是11 第11个格子的下标是10,格子的值是13 你在下标是1-9的格子都可以进行: 假设你在下标是i的格子上。其中i是1-9的任意一个数。 1.向前跳一步,跳到下标是:i + 1的格子上 2.向后跳一步,跳到下标是:i - 1的格子上 3.你还可以:假设当前格子值是v。那么你可以跳到任意的值也是v的格子上。 你在下标是0的时候不能向后跳。 你在下标是10的时候不能向前跳。 对于这组样例呢, 你看 下标:0 1 2 3 4 5 6 7 8 9 10 数值:11 22 7 7 7 7 7 7 7 22 13 开始在下标0, 跳到下标1,(值为22,可以向前跳一步),共计跳跃1次。 跳到下标9,(值为22,相同的值可以相互跳!),共计跳跃2次。 跳到下标10,(值为13,可以向前跳一步),共计跳跃3次。 如有解释失误欢迎把dayi祭天。

代码长度限制

16 KB

时间限制

1000 ms

内存限制

100 MB

//本题的bfs逻辑相对较乱,需要慢慢理解,特别是v和vis_cnt的关系
#include <bits/stdc++.h>
#define int long long
#define close_stdin  ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 50010;
int n,cnt,num[N],vis[N],step[N];

map<int,int> vis_cnt;//记录每一个数字在vector  v中是第几个
vector<int> v[N];//vector中0~v[i].size - 1储存的是相同的数字的不同位置
//例如题目中样例的数字7,它第一次出现是在第3位,因此vis_cnt[7] = 3;
//而7这个数字在第3,4,5,6,7,8,9位中都出现过,因此把3,4,5,6,7,8,9都添加进v[3]中
//便于我们在bfs时,快速寻找到7这个数字所在的位置


int c[3] = {1,-1};
void bfs(int x)
{
    int t = x;
    vis[t] = 1;
    queue<int> q;
    q.push(t);
    while (!q.empty())
    {
        t = q.front();
        q.pop();
        for (int i = 0 ; i < 2 ; i ++) //往左往右走的情况,也就是i - 1,i + 1
        {
            int tt = t + c[i];
            if (1 <= tt && tt <= n)
            {
                if (vis[tt] == 0)
                {
                    vis[tt] = 1;
                    step[tt] = step[t] + 1;
                    q.push(tt);
                }
            }
        }
        //vis_cnt[num[t]]的解释:
        //t是当前在bfs第几位
        //num[t]是第t位在数组中存的数
        //vis_cnt[num[t]]是指这个数在在v中是第几个出现的
        for (int i = 0 ; i < v[vis_cnt[num[t]]].size() ; i ++)//处理num[i] == num[j]的情况
        {
            int tt = v[vis_cnt[num[t]]][i];
            if (1 <= tt && tt <= n)
            {
                if (vis[tt] == 0)
                {
                    vis[tt] = 1;
                    step[tt] = step[t] + 1;
                    q.push(tt);
                }
            }
        }
    }
}
void solve()
{
    cnt = 1;
    cin >> n;
    for (int i = 1 ; i <= n ; i ++)
    {
        int tmp;
        cin >> tmp;
        num[i] = tmp;
        if (vis_cnt[tmp] == 0)//判断当前这种数字有没有出现过
        {
            vis_cnt[tmp] = cnt;//没出现过则标记是在第几次出现这个数
            cnt ++;
        }
        int now = vis_cnt[tmp];//这个数在第now次出现
        v[now].push_back(i);//将第i位,并入和它数字相同的vector里
    }
    bfs(1);
    cout << step[n] << endl;
}
signed main ()
{
    close_stdin;
    int T = 1;
//    cin >> T;
    while(T --) solve();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值