猜數字大小遊戲

2021-02-24 會偷懶的程序猿

偶然在別人公眾號看到一篇關於猜數字大小的題目,剛好是 LeetCode 上的題目,在 LeetCode 上又剛好看到一道很接近的擴展題,放一起整理一下

猜數字大小 Ⅰ

LeetCode 374 題

猜數字遊戲的規則如下:

每輪遊戲,我都會從 1 到 n 隨機選擇一個數字。請你猜選出的是哪個數字。如果你猜錯了,我會告訴你,你猜測的數字比我選出的數字是大了還是小了。

你可以通過調用一個預先定義好的接口 int guess(int num) 來獲取猜測結果,返回值一共有 3 種可能的情況(-1,1 或 0):

-1:我選出的數字比你猜的數字小 pick < num1:我選出的數字比你猜的數字大 pick > num0 :我選出的數字和你猜的數字一樣。恭喜!你猜對了!pick == num

示例 1

# 1 <= n <= 2^31 - 1  
# 1 <= pick <= n
輸入:n = 10, pick = 6
輸出:6

Ⅰ-1

提供了一個 int guess(int num) 的接口來判斷猜測結果,所以下意識的想到的是暴力

class Solution {
public:
    int guessNumber(int n) {
        for (int i = 1; i < n; i++)
            if (guess(i) == 0)
                return i;
        return n;
    }
};

複雜度分析:

Ⅰ-2

但是從頭開始一個個試肯定不是最優解,其次很容易想到的方法就是 二分查找

class Solution {
public:
    int guessNumber(int n) {
        int low = 1;
        int high = n;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            int res = guess(mid);
            if (res == 0)
                return mid;
            else if (res < 0)
                high = mid - 1;
            else
                low = mid + 1;
        }
        return -1;
    }
};

複雜度分析:

Ⅰ-3

看了一下答案,官方還給了一個 三分查找 的方法

在二分查找中,我們選擇中間元素作為分隔點。而在三分查找中,我們選擇兩個分隔點(比方記作 m1 和 m2),那麼給定範圍會被分成 3 個相等長度的部分。如果答案 num 比 m1 小,那麼我們對 m1 左邊的區間做三分查找。如果 num 比 m2 大,那麼我們在 m2 右邊的區域進行三分查找。否則我們在 m1 和 m2 中間區域進行三分查找。

class Solution {
public:
    int guessNumber(int n) {
        int low = 1;
        int high = n;
        while (low <= high) {
            int mid1 = low + (high - low) / 3;
            int mid2 = high - (high - low) / 3;
            int res1 = guess(mid1);
            int res2 = guess(mid2);
            if (res1 == 0)
                return mid1;
            if (res2 == 0)
                return mid2;
            else if (res1 < 0)
                high = mid1 - 1;
            else if (res2 > 0)
                low = mid2 + 1;
            else {
                low = mid1 + 1;
                high = mid2 - 1;
            }
        }
        return -1;
    }
};

複雜度分析:

猜數字大小 Ⅱ

LeetCode 375 題

我們正在玩一個猜數遊戲,遊戲規則如下:
我從 1 到 n 之間選擇一個數字,你來猜我選了哪個數字。
每次你猜錯了,我都會告訴你,我選的數字比你的大了或者小了。
然而,當你猜了數字 x 並且猜錯了的時候,你需要支付金額為 x 的現金。直到你猜到我選的數字,你才算贏得了這個遊戲。

示例:

n = 10, 我選擇了8.

第一輪: 你猜我選擇的數字是5,我會告訴你,我的數字更大一些,然後你需要支付5塊。
第二輪: 你猜是7,我告訴你,我的數字更大一些,你支付7塊。
第三輪: 你猜是9,我告訴你,我的數字更小一些,你支付9塊。

遊戲結束。8 就是我選的數字。

你最終要支付 5 + 7 + 9 = 21 塊錢。
給定 n ≥ 1,計算你至少需要擁有多少現金才能確保你能贏得這個遊戲。

仔細體會一下這道題,這道題 不是找出如何最快猜出選中的數的方法,而是一個策略的權衡,在最壞的情況下最便宜猜出選中的數

比方說:

n=5
1 2 3 4 5
# 假設答案是 5 

根據二分法,如果我們一開始猜 3 ,那麼我們下一次肯定猜 4 ,最終總代價為 4+3=7
而實際上,我們只要先猜 4, 對了和小了的總代價就是 4,猜大了,在猜 2,這時候不管大了小了還是對了,都定位出真正的數字,此時的總代價是 6, 而為了保證贏,最小的總代價就是 6

結合上面的介紹,實際上就是在 (1,n) 範圍內考慮猜中數字的最壞情況下的最小代價

當我們從 (1,n) 中隨機取個數字 x, 如果沒有猜中,則根據結果,在 (1,x-1) 或者 (x+1,n) 的範圍繼續猜數字,考慮到最壞情況,所以總體最小代價是:

cost(1,n) = x + max( cost(1,x-1), cost(x+1,n) )

Ⅱ-1

根據這個邏輯,直接暴力遞歸

class Solution {
public:
    int cost(int left, int right) {
        if (left >= right)
            return 0;
        int res = INT_MAX;
        for (int i = left; i<=right; i++) {
            int tmp = i + max( cost(left, i-1), cost(i+1, right) );
            res = min(tmp, res) ;
        }
        return res;
    }

    int getMoneyAmount(int n) {
        return cost(1,n);
    }
};

複雜度分析:

Ⅱ-2

暴力遞歸確實可以解決這個問題,但是遞歸會導致出現很多重複的計算,所以我們需要對結果進行保存,防止重複計算

#include <map>
#include <algorithm>
using namespace  std;
class Solution {
public:
    int cost(map<string, int> &record, int left, int right) {
        if (left >= right)
            return 0;
        
        string key = to_string(left) + "-" +to_string(right);
        map<string, int>::iterator find_res = record.find(key);
        if ( find_res != record.end())
            return find_res->second;

        int res = INT_MAX;
        for (int i = left; i<=right; i++) {
            int tmp = i + max( cost(record, left, i-1), cost(record, i+1, right) );
            res = min(tmp, res) ;
        }
        record[key] = res;
        return res;
    }

    int getMoneyAmount(int n) {
        map<string, int> record = {};
        return cost(record, 1, n);
    }
};

我用 map 存了計算的結果, 在計算的時候,如果 map 中直接有,就不用遞歸了,雖然效率變高了,實際上複雜度還是:

上面這2種寫法在 Leetcode 上提交的最後都會因為 超出時間限制 而失敗,無非前一個是在 n=18 後面一個是在 n=115, 時間複雜度並沒有明顯降下來,所以還是需要換個思路

Ⅱ-3

最後當然離不開動態規劃,我不太精通這個,但是看到一篇解析的很清楚的文章推薦給大家

https://leetcode-cn.com/problems/guess-number-higher-or-lower-ii/solution/dong-tai-gui-hua-c-you-tu-jie-by-zhang-xiao-tong-2/

class Solution {
public:
    int getMoneyAmount(int n) {
        if(n==1)
            return 0;

        int dp[n+1][n+1];
        for(int i=0;i<=n;i++){
            for(int j=0;j<=n;j++){
                dp[i][j]=INT_MAX;
            }
        }
        for(int i=0;i<=n;i++){
            dp[i][i]=0;
        }

        for(int j=2;j<=n;j++){
            for(int i=j-1;i>=1;i--){
                for(int k=i+1;k<=j-1;k++){
                    dp[i][j]=min(k+max(dp[i][k-1],dp[k+1][j]),dp[i][j]);
                }
                dp[i][j]=min(dp[i][j],i+dp[i+1][j]);
                dp[i][j]=min(dp[i][j],j+dp[i][j-1]);
            }
        }
        return dp[1][n];
    }
};

複雜度分析:

相關焦點

  • 【C語言程序設計】—最近超火的小遊戲—【數字炸彈】!
    我們可以稱呼這個遊戲為《數字炸彈》。遊戲的原理是這樣:每一輪電腦從 1 到 100 中隨機抽一個整數。電腦請求你猜這個數字,因此你要輸入一個 1 到 100 之間的整數。電腦將你輸入的數和它抽取的數進行比較,並告知你的數比它的數大了還是小了。然後它會再次讓你輸入數字,並告訴你比較的結果。
  • 手機遊戲「我畫你猜」點燃白領學英文熱情-我畫你猜,手機遊戲,學...
    當水果不再瘋狂,當小鳥不再憤怒,當多數智慧型手機用戶都端著屏幕在畫點什麼時,社交遊戲Draw something(我畫你猜)獨佔鰲頭的時刻來臨了。「我畫你猜」是一款通過用戶與朋友或者對手之間的互動,共同完成的遊戲。
  • 數學思維遊戲:猜點數|1-5年級
    ◆ 指點迷津猜點數遊戲是一個古老又年輕的遊戲,裡面充滿了許多數學上的學問,只要我們動腦筋,就能找到這些「學問」。可以從學具盒中找出骰子來玩,也可用一塊的橡皮切成骰子,在上面寫上數字來玩。特別注意寫骰子上數字的方法,即1與6對應,2與5對應,3與4對應寫才對。
  • 看圖猜成語
    看圖猜成語 休閒益智 大小: 51.54M 版本: 5.72
  • 天堂鳥偶爾也出正經的好遊戲!
    回想當年有一年初五是在姨夫家過的,那時姨夫家的電腦很高級,以前玩大航海2單挑要死機的,他的電腦就跑得動,後來小夥伴們就玩了一款比較歡樂的遊戲,當時只記得裡面有武田信玄,現在回想起來這竟然還是部PC上的日本戰國遊戲!遊戲的名字叫做《戰國時代》各種黑日本大大名好吧,重新打開這個遊戲驚呆了,竟然是大名鼎鼎的天堂鳥出品的。
  • 大森林幼兒英語單詞卡遊戲大全(下)
    數字 Numbers把 從one 到 five 閃卡排成一排。展示另外五張閃卡,然後把它們面朝下放,每張數字閃卡下放一張,指出每個數字,然後要求小朋友猜底下的詞彙。Tina看閃卡,然後它把閃卡翻過來,如果小朋友們猜對了,用其他剩餘的閃卡重複這個遊戲。
  • 公平的進行異地猜硬幣遊戲——量子猜硬幣協議
    在發表BB84協議的同一篇的論文中,兩位作者還提出了一個很有意思的「量子猜硬幣協議」(Quantum Coin Tossing)。「量子猜硬幣協議」是解決這樣一個問題:在不同地點的兩個人,如何公平的進行猜硬幣遊戲?就是一個人丟硬幣,另一個人來猜。這裡,兩個人之間是完全沒有信任的,哪怕視頻連線,猜硬幣的一方都懷疑丟硬幣的一方是不是準備好了兩套視頻,以保證自己能贏。
  • 益智遊戲:看圖猜成語,看到這兩個字,你最先想到的是什麼?
    親愛的小夥伴們~大家好呀~今天的益智遊戲已到~是時候展示真正的技術了~看圖猜成語考驗你的邏輯思維能力TOP8看圖猜成語,看到這兩個字,你最先想到的是什麼益智遊戲益智遊戲TOP6:零加零等於一,猜一個成語。
  • 你畫我猜遊戲全球熱爆 網友稱手笨英文爛傷不起
    這款由休閒遊戲公司OMGPOP推出的畫圖猜字遊戲,發布僅一個月下載量就突破1200萬次,日活躍用戶高達710萬,一躍成為App Store和Android Market中排名第一的遊戲。它是一款社交遊戲,要求你跟好友合作完成。從三個備選英文單詞中選一個畫一幅畫,發給好友猜是什麼單詞,猜對兩人都有金幣。有意思的是,你的整個繪畫過程對方都能看到,畫得太爛還會給對方增加歡樂哦!
  • 老外挑戰「未知遊戲」,黑洞裡有什麼?結果你猜怎麼著
    老外挑戰「未知遊戲」,黑洞裡有什麼?結果你猜怎麼著 2020-11-16 12:16 來源:科技看天下
  • 陸晨:論「猜」的重要性
    下面是一道簡單的不定方程題目,大家可以試一下: 經過不斷的學習,我才知道,原來「猜」就是數學中的一種重要方法,在課堂中循規蹈矩所學習的演繹推理,都是象牙塔裡被無限美化的遊戲,當我們踏出「陽春白雪」的課堂,走進真實複雜殘酷的現實世界,面對的是數不勝數的信息不對稱性的挑戰,整個人生就是在不斷地解決一個又一個不定方程,充滿了不確定性
  • 第五人格:看圖猜成語!猜對兩個是高手,五個全部猜到的是大神
    周末到了,經過了一周的忙碌,今天給大家帶來一個娛樂放鬆的小遊戲吧。遊戲內容很簡單:利用第五人格裡的圖片和梗猜成語。首先,簡單示範一下這個遊戲的玩法。如下圖:這幅圖裡面,有「杯子」,有「弓箭」,還有「蛇的影子」,所以我們很容易聯想到「杯弓蛇影」這個成語。就是這麼簡單!你已經了解了玩法了,現在讓我們開始第五人格版的看圖猜成語吧!玩家自製的律師紫皮鎮樓!
  • 情迷數字遊戲「九宮格」
    新東方網>英語>英語學習>英語閱讀>雙語新聞>正文情迷數字遊戲「九宮格」 2007-12-21 14:28 來源:環球時報 作者:
  • 小學英語老師常用的課堂操練遊戲100例
    6.木頭人 wooden child遊戲說明:教師或選一名學生背對學生進行單詞操練,當教師或學生轉過身時其他學生保持原來的動作變成木頭人。7.吹氣球 blow the balloons遊戲說明:學生邊說單詞邊做吹氣球的動作,聲音隨著氣球的大小發生相應的變化,用於操練單詞。
  • 用7個數字代表排列五遊戲組合7種類型,有利於選擇數字組合
    近來有朋友詢問,關於排列五(排列5)遊戲的數字選擇方法,以前一直沒時間整,最近因關在家裡,不能出門,因此,多了點時間,順便整理總結了一部分個,人認為有用的、排列五遊戲的數字選擇方法,希望對朋友玩排列五遊戲能有所幫助,其實,每個彩民都有自己喜歡的方法,只是因個人的選擇習慣不一樣了。
  • 一些遊戲玩法整理
    一些現代小說,有時候會涉及一些遊戲賭局的場景,比如在某個大遊輪上什麼的。今日就收集一些常見的遊戲玩法。註:首先聲明賭博是違法的哈,這裡收集只是為了小說虛擬之中使用。1.比大小這是很常見的運氣類遊戲,偶爾ktv聚會都會玩。玩法也簡單,就是看誰運氣好猜中了是「大」還是「小」。
  • 兩個好玩的數學遊戲
    這兩個數學遊戲,為佘飛所發明,個人認為相當有意思,我們玩兒了好長時間了,作為無聊繁重的課業之餘的休閒娛樂活動。 兩人輪流從1~20中寫數字,誰寫下的數字中有4個之和為40誰就是贏家。寫數字的時候每一輪都是分別寫好然後再同時亮出來,已經寫過的數字以後不可以再重複寫。如果出現某一輪兩人寫的數各自可以湊成和為40,則這一輪兩人寫下的數字被劃掉,而且以後也不準再寫這個數。
  • 英語課堂常用遊戲100例,活躍的課堂氣氛就靠它們了!
    7.吹氣球 blow the balloons 遊戲說明:學生邊說單詞邊做吹氣球的動作,聲音隨著氣球的大小發生相應的變化,用於操練單詞。 10.大小聲 opposite tune 遊戲說明:學生與教師進行唱反調的遊戲,教師聲音大,學生聲音小;教師聲音小,學生的聲音相應變大,可用於單詞或簡單句型的操練。
  • 通過這30個遊戲,培養孩子做數感訓練和學習!
    識數是幼兒園小班階段的要求,具體包括:能流暢地數數、準確地認數、有大小概念。訓練先從10以內的數字開始,再遞進到十位數的讀數,然後到百位數。玩法1:口令取數手邊準備好所需範圍的數字棋,爸媽發出口令,比如:拿數字7,然後娃根據口令去找到正確的數字棋子。也可以反過來,隨機抓取一顆數字棋,讓娃讀出上面的數字。
  • 比拼詩詞儲備量必備遊戲!看拼音猜詩歌,比飛花令更加好玩!
    「感時花濺淚,恨別鳥驚心」;「忽如一夜春風來,千樹萬樹梨花開」;「當窗理雲鬢,對鏡貼花黃」......除了飛花令,你還想不想玩玩其它形式的詩詞遊戲呢?一起來看看「看拼音猜詩歌」這一遊戲吧。如果把一句完整的詩詞的每個字打散,胡亂排序,並且是以拼音的形式呈現的,你還能不能猜出來呢?