1340. 跳跃游戏 V

题目描述

给你一个整数数组 arr 和一个整数 d 。每一步你可以从下标 i 跳到:

  • i + x ,其中 i + x < arr.length 且 0 < x <= d 。
  • i - x ,其中 i - x >= 0 且 0 < x <= d 。

除此以外,你从下标 i 跳到下标 j 需要满足:arr[i] > arr[j]arr[i] > arr[k] ,其中下标 k 是所有 ij 之间的数字(更正式的,min(i, j) < k < max(i, j))。

你可以选择数组的任意下标开始跳跃。请你返回你 最多 可以访问多少个下标。

请注意,任何时刻你都不能跳到数组的外面。

解答

感觉其实和前两个跳跃游戏有异曲同工之妙,都是在跳转中判断怎么跳,可不可以跳,跳多远。

所以第一种尝试的方法就是顺序遍历+深搜,因为可以选择数组的任意下标开始跳跃,还需要枚举起点(虽然感觉其实最后是强连通的,瞎说的,因为跳转具有方向性,并且一次只能选择一个方向跳转)

class Solution {
public:
    bool f[1002]={0};
    int search(int i, int d,vector<int>& arr)
    {
        int j=1;
        int n=arr.size();
        int sum=0;
        int ans=0;
        while (j<=d && i-j>-1 && arr[i-j]<arr[i])
        {
            if (!f[i-j])
            {
                sum=1;
                f[i-j]=1;
                sum+=search(i-j,d,arr);
                if(sum>ans) ans=sum;
                f[i-j]=0;
            }
            j++;
        }
        j=1;
        while (j<=d && i+j<n && arr[i+j]<arr[i])
        {
            if (!f[i+j])
            {
                sum=1;
                f[i+j]=1;
                sum+=search(i+j,d,arr);
                if(sum>ans) ans=sum;
                f[i+j]=0;
            }
            j++;
        }
        return ans;
    }


    int maxJumps(vector<int>& arr, int d) {
        int ans=0;
        int n=arr.size();
        for (int i=0; i<n; i++)
        {
            f[i]=1;
            int sum=1;
            sum += search(i,d,arr);
            if (sum>ans)
              ans=sum;
            f[i]=0;
        }
        return ans;
    }
};

很显然的超出了时间限制。

为了节省时间,如果之前搜索过的点,那么就可以直接存储并且拿过来用。

class Solution {
public:
    bool f[1002]={0};
    int a[1002]={0};
    int search(int i, int d,vector<int>& arr)
    {
        if (a[i]) return a[i]-1;
        int j=1;
        int n=arr.size();
        int sum=0;
        int ans=0;
        while (j<=d && i-j>-1 && arr[i-j]<arr[i])
        {
            if (!f[i-j])
            {
                sum=1;
                f[i-j]=1;
                sum+=search(i-j,d,arr);
                if(sum>ans) ans=sum;
                f[i-j]=0;
            }
            j++;
        }
        j=1;
        while (j<=d && i+j<n && arr[i+j]<arr[i])
        {
            if (!f[i+j])
            {
                sum=1;
                f[i+j]=1;
                sum+=search(i+j,d,arr);
                if(sum>ans) ans=sum;
                f[i+j]=0;
            }
            j++;
        }
        return ans;
    }


    int maxJumps(vector<int>& arr, int d) {
        int ans=0;
        int n=arr.size();
        for (int i=0; i<n; i++)
        {
            f[i]=1;
            int sum=1;
            sum += search(i,d,arr);
            if (sum>ans)
              ans=sum;
            a[i]=sum;
            f[i]=0;
        }
        return ans;
    }
};

记忆化搜索提高了10个点的通过率,但是依旧失败了。个人感到有一点问题:因为不能保证剔除重复搜索的点。不存在的,因为条件的问题,不会出现环,还是DP做的

class Solution {
public:
    int dp[1002]={0};
    void search(int i, int d,vector<int>& arr)
    {
           int n=arr.size();
           int j=1;
           while (j<=d && i-j>-1 && arr[i]>arr[i-j])
           {
               if (!dp[i-j]) search(i-j,d,arr);
               dp[i]=max(1+dp[i-j],dp[i]);
               j++;
           }
            j=1;
           while (j<=d && i+j<n && arr[i]>arr[i+j])
           {
               if (!dp[i+j]) search(i+j,d,arr);
               dp[i]=max(1+dp[i+j],dp[i]);
               j++;
           }
          return; 
    }

    int maxJumps(vector<int>& arr, int d) {
        int n=arr.size();
        int ans=0;
        for (int i=0; i<n; i++)
        {
          if (!dp[i])
          {
           int j=1;
           while (j<=d && i-j>-1 && arr[i]>arr[i-j])
           {
               if (!dp[i-j]) search(i-j,d,arr);
               dp[i]=max(1+dp[i-j],dp[i]);
               j++;
           }
           j=1;
           while (j<=d && i+j<n && arr[i]>arr[i+j])
           {
               if (!dp[i+j]) search(i+j,d,arr);
               dp[i]=max(1+dp[i+j],dp[i]);
               j++;
           }
          } 
          if (dp[i]>ans) ans=dp[i];
        }
        return ans+1;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值