日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

leetcode 403青蛙过河

發布時間:2024/1/1 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 leetcode 403青蛙过河 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

403. 青蛙過河

  • 題目
    • 分析
    • 超時代碼
      • 代碼1
      • 代碼2
      • 代碼3
    • 通過代碼
      • 代碼4
      • 代碼5
      • 代碼6

題目

一只青蛙想要過河。 假定河流被等分為 x 個單元格,并且在每一個單元格內都有可能放有一石子(也有可能沒有)。 青蛙可以跳上石頭,但是不可以跳入水中。

給定石子的位置列表(用單元格序號升序表示), 請判定青蛙能否成功過河(即能否在最后一步跳至最后一個石子上)。 開始時, 青蛙默認已站在第一個石子上,并可以假定它第一步只能跳躍一個單位(即只能從單元格1跳至單元格2)。

如果青蛙上一步跳躍了 k 個單位,那么它接下來的跳躍距離只能選擇為 k - 1、k 或 k + 1個單位。 另請注意,青蛙只能向前方(終點的方向)跳躍。

請注意:

石子的數量 ≥ 2 且 < 1100; 每一個石子的位置序號都是一個非負整數,且其 < 231; 第一個石子的位置永遠是0。

示例 1:

[0,1,3,5,6,8,12,17]

總共有8個石子。
第一個石子處于序號為0的單元格的位置, 第二個石子處于序號為1的單元格的位置,
第三個石子在序號為3的單元格的位置, 以此定義整個數組…
最后一個石子處于序號為17的單元格的位置。

返回 true。即青蛙可以成功過河,按照如下方案跳躍:
跳1個單位到第2塊石子, 然后跳2個單位到第3塊石子, 接著
跳2個單位到第4塊石子, 然后跳3個單位到第6塊石子,
跳4個單位到第7塊石子, 最后,跳5個單位到第8個石子(即最后一塊石子)。

示例 2:

[0,1,2,3,4,8,9,11]

返回 false。青蛙沒有辦法過河。
這是因為第5和第6個石子之間的間距太大,沒有可選的方案供青蛙跳躍過去。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/frog-jump

分析

動規的題目,這個題的狀態應該就是所處的位置和能跳的距離.按照這個來定.
查找下一個石頭有三種找法

  • 遍歷石頭,找dis-1<=stones[i]-stones[now]<=dis+1的 O(n)
  • 通過距離,在stones里找stones[i]=dis||dis+1||dis-1的,這種一般是二分查找 O(log(n))
    bool check(vector& stones,int now,int jump,vector<vector>& memo)
    check的返回值就是對于從now索引的石頭開始跳,現在跳的距離是jump的能不能到最后一塊石頭,memo的值也和check返回值一一對應
  • 事先將所有的石頭都放到一個set里,這樣就可以在now,jump的時候查找set里是否有set.count(stones[now]+jump),來確定是否有需要的石頭.
  • jumpsize的大小不會超過1001,因為一共有1000塊石頭,每一步就算只跳到下一塊,那么最多跳1000下,一下最多jumpsize增加1,所以jumpsize最多為1001.就可以在一個stones.size()大小的存儲了

    這題我做吐了,寫了兩種都超時,又模仿著官方題解寫了兩種,又超時.

    回溯的基本的思路:

    bool check(vector<int>& stones,int now,int jump,vector<vector<bool>>& memo){if(memo[now][jump])return memo[now][jump];int tmp=search(now+1,sz-1,stones[now]+jump,stones);if(tmp!=-1&&check(stones,tmp,jump,memo)){memo[now][jump]=true;return true;}tmp=search(now+1,sz-1,stones[now]+jump-1,stones);if(tmp!=-1&&check(stones,tmp,jump-1,memo)){memo[now][jump-1]=true;return true;}tmp=search(now+1,sz-1,stones[now]+jump+1,stones);if(tmp!=-1&&check(stones,tmp,jump+1,memo)){memo[now][jump+1]=true;return true;}memo[now][jump]=now==sz-1;return memo[now][jump];

    首先看備忘錄里有沒有這個值,之后嘗試三種步子大小.如果有一種成功了,就return true走掉了.三種都沒有成功的就說明它沒有下一步了,檢查它是否是最后一塊石頭(這個也可以在開頭檢查)

    超時代碼

    代碼1

    class Solution { public:bool res=false;int sz;int find(int left,int target,vector<int>&stones){int right=sz-1;while(left<=right){int mid=left+(right-left)/2;if(stones[mid]==target) return mid;else if(stones[mid]>target) right=mid-1;else left=mid+1;}return -1;}void backtrace(int now,int step,vector<int>& stones){//找到下一個石頭if(res) return;int tmp=find(now+1,stones[now]+step,stones);if(tmp==-1) return;if(tmp==sz-1) {res=true; return;}backtrace(tmp,step+1,stones);backtrace(tmp,step,stones);if(step-1>0)backtrace(tmp,step-1,stones);}bool canCross(vector<int>& stones) {sz=stones.size();;backtrace(0,1,stones);return res;} };

    這個寫的就是單純的回溯(過了16個),這個超時我認的
    由于dp就是帶備忘的回溯,所以我就加了個數組記錄

    代碼2

    class Solution { public:int sz;bool check(vector<int>& stones,int now,int jump,vector<vector<bool>>& memo){if(memo[now][jump])return memo[now][jump];for(int i=now+1;i<sz;i++){int dis=stones[i]-stones[now];if(dis>=jump-1&&dis<=jump+1){if(check(stones,i,dis,memo)){memo[now][dis]=true;return true;}}}memo[now][jump]=now==sz-1;return memo[now][jump];}bool canCross(vector<int>& stones) {sz=stones.size();vector<vector<bool>> memo(sz,vector<bool>(sz,false));return check(stones,0,0,memo); } };

    這個跟官方的題解寫的差不多啊.為啥還是超時只過16個
    嗯,我不在數組里遍歷了,再優化下,改成二分查找,這樣就是找三個指定的值了

    代碼3

    class Solution { public:int sz;int search(int left,int right,int tar,vector<int> &stones){while(left<=right){int mid=left+(right-left)/2;if(stones[mid]==tar) return mid;else if (stones[mid]<tar) left=mid+1;else right=mid-1;}return -1;}bool check(vector<int>& stones,int now,int jump,vector<vector<bool>>& memo){if(memo[now][jump])return memo[now][jump];int tmp=search(now+1,sz-1,stones[now]+jump,stones);if(tmp!=-1&&check(stones,tmp,jump,memo)){memo[now][jump]=true;return true;}tmp=search(now+1,sz-1,stones[now]+jump-1,stones);if(tmp!=-1&&check(stones,tmp,jump-1,memo)){memo[now][jump-1]=true;return true;}tmp=search(now+1,sz-1,stones[now]+jump+1,stones);if(tmp!=-1&&check(stones,tmp,jump+1,memo)){memo[now][jump+1]=true;return true;}memo[now][jump]=now==sz-1;return memo[now][jump];}bool canCross(vector<int>& stones) {sz=stones.size();vector<vector<bool>> memo(sz+1,vector<bool>(sz+1,false));return check(stones,0,0,memo); } };

    做到這我快哭了,咋還是超時只過16個.這我改的跟沒優化的一樣…

    通過代碼

    下面每一個通過對代碼都有一些額外的小技巧,我是想不到,也是參考別人的

    代碼4

    class Solution { public:int sz;unordered_map<int,bool> memo;bool check(vector<int>& stones,int now,int jump){int key = now | jump << 11;if(now>=sz-1) return true;if(memo.count(key)) return memo[key];for(int i=now+1;i<sz;i++){int dis=stones[i]-stones[now];if(dis>=jump-1&&dis<=jump+1){if(check(stones,i,dis)){return memo[key]=true;}}else if(dis>jump+1) break;}return memo[key]=false;}bool canCross(vector<int>& stones) {sz=stones.size();return check(stones,0,0); } };

    這個代碼是參考大佬的,亮點在于使用了狀態的壓縮,即將now和jump壓縮成一個數,然后存在unordered_map里,在備忘錄里提出的速度就比較快,還節省空間(使用map也能過,就是慢點)
    菜雞的疑問,這vector<vector> 就這么慢嗎,
    map.count(key) ->返回 map中key的個數,因為map中key唯一,所以有就返回1,沒有就返回0
    map.find(key) ->返回值為key的迭代器,有就返回正常迭代器,沒有就返回map.end()

    代碼5

    回溯,剪枝

    //12ms,9MB class Solution { public:bool res=false;int sz;int find(int left,int target,vector<int>&stones){int right=sz-1;while(left<=right){int mid=left+(right-left)/2;if(stones[mid]==target) return mid;else if(stones[mid]>target) right=mid-1;else left=mid+1;}return -1;}void backtrace(int now,int step,vector<int>& stones){//找到下一個石頭if(res) return;int tmp=find(now+1,stones[now]+step,stones);if(tmp==-1) return;if(tmp==sz-1) {res=true; return;}backtrace(tmp,step+1,stones);backtrace(tmp,step,stones);if(step-1>0)backtrace(tmp,step-1,stones);}bool canCross(vector<int>& stones) {sz=stones.size();for (int i = 1; i < stones.size(); ++i) {if (i > 3 && stones[i - 1] * 2 < stones[i]){return false;}}backtrace(0,1,stones);return res;} };

    這個代碼就是"代碼1"加了剪枝,結果雙百.
    剪枝

    for (int i = 1; i < stones.size(); ++i) {if (i > 3 && stones[i - 1] * 2 < stones[i]){return false;}}

    這個剪枝就是根據第i塊石頭的時候最多跳i個單位(這是i及以前的石頭能跳的最遠距離),所以所以如果下一塊石頭在2*stones[i]外面,那就跳不到了,只能是false;我是真沒想到!

    代碼6

    //412ms,37MB class Solution { public:int sz;unordered_map<int,unordered_set<int>> map;bool canCross(vector<int>& stones) {sz=stones.size();for(int i=0;i<sz;i++){map[stones[i]]=unordered_set<int>();}map[0].insert(0);for(int i=0;i<sz;i++){for(const int &step:map[stones[i]]){for(int j=step-1;j<=step+1;++j){if(j>0&&map.count(stones[i]+j)){map[stones[i]+j].insert(j);}}}}return map[stones[sz-1]].size()>0;} };

    這個算法是官方的最后一種動態規劃的解法,具體就是對每一個stones[i]存入map,每個stones[i]對應一個set,里面記錄到達stones[i]的上一個步長,在stones[i]進行狀態轉移的時候,就可以使用set里面的步長每一個的+1&&-1的步長進行下一塊石頭的嘗試,如果有,就將現在的步長記入下一塊石頭的set里.
    初始就是在第0(索引)塊的時候步長為0,保證第一步就是只有step=1.
    最終結果就是看最后一塊石頭的set里是否有東西,因為set就是記錄到達的上一步長度,有就表示可以到.
    tips:
    map里套set的構造

    map[stones[i]]=unordered_set<int>();

    map里套set的set遍歷

    for(const int &step:map[stones[i]])

    const不能少,否則報錯

    感覺還是最后一種方法是正道,回溯剪枝雖然快,但感覺是數據水,出的都是0,1,2,999這種,正常的剪肯定剪不了多少,剪不了還是要回溯,回溯就太慢了.

    總結

    以上是生活随笔為你收集整理的leetcode 403青蛙过河的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 亚洲精品视频一区二区 | 男男做爰猛烈叫床爽爽小说 | 国产一区二区三区四区在线观看 | 婷婷啪啪 | 污污免费视频 | 伊人婷婷在线 | 天美视频在线观看 | 亚洲高清在线视频 | 人妻少妇久久中文字幕 | 黄网站在线观看 | 一级a毛片免费观看久久精品 | 久久刺激 | 天堂最新资源在线 | 国产三级精品在线 | 日韩视频一区在线观看 | 福利色播| 在线亚洲区| 91精品观看 | 成人性生交大片免费看中文 | 青娱乐超碰在线 | 日本一区二区在线不卡 | 神马久久久久久久 | 日韩成人在线免费观看 | 91成人小视频 | 中文av免费 | 日日夜夜2017 | 在线视频欧美日韩 | 懂色a v | 免费久久一级欧美特大黄 | 国产熟妇乱xxxxx大屁股网 | 国外成人性视频免费 | 奇米四色影视 | 国产一级片网站 | www.sesehu| 永久免费视频网站直接看 | 国产美女黄网站 | 超碰在线国产 | 久久资源av | 请用你的手指扰乱我吧 | 中国特级黄色片 | 欧美日韩一区视频 | 男人天堂成人网 | 欧美在线免费 | 欧美精品免费视频 | 亚洲黄色在线观看视频 | 国产精品久久久无码一区 | 中文字幕一区二区三区精华液 | 亚洲综合激情五月久久 | 色爱av综合 | 不卡av免费观看 | 高清毛片aaaaaaaaa片 | 欧美一级大黄 | 91色爱| 中文久久久 | 亚洲日本在线观看 | 日本一区二区三区视频免费看 | 香蕉视频在线免费播放 | av资源站| 亚洲天堂2013 | 手机在线观看毛片 | 免费激情小视频 | 久久久久国产一区二区三区潘金莲 | 日本人dh亚洲人ⅹxx | 超碰97人人爱 | 澳门av网站| 69色| 日韩一级欧美 | 亚洲成人一区在线 | 日本一区二区高清不卡 | 操穴影院 | 少妇一级淫片aaaaaaa | 亚洲国产成人一区二区 | 爱操在线 | 亚洲爱色 | 欧美日韩国产精品一区二区 | 成人高潮片| 人妻少妇精品一区二区三区 | 欧美精品福利视频 | 午夜视频免费在线观看 | 视频在线一区二区三区 | 美女破处视频 | 久久久久久蜜桃一区二区 | 韩日欧美| 美妇湿透娇羞紧窄迎合 | 艳妇乳肉豪妇荡乳av无码福利 | jzzijzzij日本成熟少妇 | 国产一区二区三区在线视频 | 国产精品69久久久久 | 欧美日本韩国一区二区三区 | 亚洲精品97久久 | 亚洲中文字幕无码一区 | 青青操狠狠干 | 久久久精品毛片 | 国产做爰xxxⅹ高潮视频12p | 欧美日韩成人一区二区 | 亚洲国产成人综合 | 超碰在线免费公开 | 亚洲精品在线免费 | 成年人免费小视频 |