元宵節(jié)無(wú)法出門鬧花燈于购,那么在家用程序解數(shù)獨(dú)吧

今天是元宵佳節(jié)袍睡,又恰逢周末,原本應(yīng)該出門鬧花燈肋僧,但是當(dāng)前的新冠疫情讓大家關(guān)門閉戶異常冷清斑胜。
猜燈謎是元宵節(jié)的傳統(tǒng)項(xiàng)目,記得小時(shí)候在老家每個(gè)元宵節(jié)都打著燈籠出門嫌吠,大街上滿是彩燈和燈謎止潘,城市還專門組織有大型的煙火表演,人山人海熱鬧非凡辫诅。
既然沒(méi)法出門凭戴,在家也能做些個(gè)游戲,例如用看怎么用代碼來(lái)解決數(shù)獨(dú)問(wèn)題吧:)
我們有如下數(shù)獨(dú)問(wèn)題:


image.png

這是一個(gè)9X9的數(shù)獨(dú)矩陣炕矮,其中需要保證:

  1. 整數(shù)1~9在每一行中只能出現(xiàn)一次
  2. 整數(shù)1~9在每一列中只能出現(xiàn)一次
  3. 在其中9個(gè)3X3的子矩陣中么夫,整數(shù)1~9也只能出現(xiàn)一次

通過(guò)以上限制,我們期望得到以下的答案:


image.png

為了能用程序來(lái)解決數(shù)獨(dú)問(wèn)題肤视,我們用一個(gè)二維字符數(shù)組來(lái)代表字符矩陣:

        char[][] board = {
                {'5', '3', '.', '.', '7', '.', '.', '.', '.'},
                {'6', '.', '.', '1', '9', '5', '.', '.', '.'},
                {'.', '9', '8', '.', '.', '.', '.', '6', '.'},
                {'8', '.', '.', '.', '6', '.', '.', '.', '3'},
                {'4', '.', '.', '8', '.', '3', '.', '.', '1'},
                {'7', '.', '.', '.', '2', '.', '.', '.', '6'},
                {'.', '6', '.', '.', '.', '.', '2', '8', '.'},
                {'.', '.', '.', '4', '1', '9', '.', '.', '5'},
                {'.', '.', '.', '.', '8', '.', '.', '7', '9'}
        };

其中未知的單元格用字符'.'來(lái)表示档痪,期望實(shí)現(xiàn)個(gè)函數(shù)將所有'.'替換為'1'~'9'的字符并保證數(shù)獨(dú)矩陣的合法性。
我們可以將此問(wèn)題分解為兩個(gè)子問(wèn)題來(lái)考慮:檢驗(yàn)放入一個(gè)值后邢滑,是否滿足數(shù)獨(dú)矩陣合法性腐螟;遞歸遍歷整個(gè)矩陣,并在未知位置依次試探放入'1'~'9'并檢查合法性殊鞭,如果不合法則使用下一個(gè)值進(jìn)行回溯分析遭垛。

校驗(yàn)當(dāng)前單元格放入數(shù)值后的合法性

要校驗(yàn)合法性,滿足數(shù)據(jù)矩陣所要求的三個(gè)規(guī)則即可:

    /**
     * 校驗(yàn)放入當(dāng)試探值是否能保證數(shù)獨(dú)矩陣的正確性
     *
     * @param board 數(shù)獨(dú)矩陣
     * @param x x軸坐標(biāo)代表列號(hào)
     * @param y y軸坐標(biāo)代表行號(hào)
     * @param c 試探放入的值操灿,為'1'~'9'的整數(shù)
     * @return 返回true當(dāng)校驗(yàn)通過(guò)
     */
    private boolean isValid(char[][] board, int x, int y, char c) {
        //3*3方塊的開(kāi)始y軸號(hào)
        int regionRow = 3 * (y / 3);
        //3*3方塊的開(kāi)始x軸坐標(biāo)
        int regionCol = 3 * (x / 3);
        for (int i = 0; i < 9; i++) {
            //檢查每一行的正確性
            if (board[i][x] == c) return false;
            //檢查每一列的正確性
            if (board[y][i] == c) return false;
            //檢查3*3方格內(nèi)的正確性
            if (board[regionRow + i / 3][regionCol + i % 3] == c) return false;
        }
        return true;
    }

遞歸回溯分析整個(gè)矩陣

我們循環(huán)遍歷整個(gè)二維數(shù)組锯仪,當(dāng)遇到'.'后試探放入'1' ~ '9‘的整數(shù)并使用上面的方法進(jìn)行正確性分析,如果正確后趾盐,遞歸調(diào)用下一個(gè)單元格庶喜,如果當(dāng)前單元格放入'1' ~ '9'都不能得到合法的數(shù)獨(dú)矩陣小腊,則說(shuō)明之前單元格放入了錯(cuò)誤的值,此時(shí)回溯到上一次遞歸久窟,試探放入下一個(gè)合法的整數(shù)秩冈,繼續(xù)進(jìn)行遞歸分析:

    /**
     * 遞歸函數(shù),當(dāng)?shù)玫胶戏ǖ臄?shù)據(jù)矩陣后返回true
     * 
     * @param board 數(shù)獨(dú)矩陣
     * @param x x軸坐標(biāo)代表列號(hào)
     * @param y y軸坐標(biāo)代表行號(hào)
     * @return
     */
    private boolean check(char[][] board, int x, int y) {
        for (; y < 9; y++) {
            //如果輸入的列號(hào)溢出斥扛,則直接進(jìn)入下一行從第一列開(kāi)始
            for (; x < 9; x++) {
                if (board[y][x] != '.') continue;
                //當(dāng)前值為'.'時(shí)入问,
                //依次試探放入'1'~'9'的值來(lái)看是否滿足合法的數(shù)獨(dú)矩陣
                for (char c = '1'; c <= '9'; c++) {
                    //放入后不合法,直接忽略稀颁,嘗試下一個(gè)值
                    if (!isValid(board, x, y, c)) continue;
                    board[y][x] = c;
                    //當(dāng)前位置試探放入值c后芬失,遞歸調(diào)用下一列
                    if (check(board, x + 1, y)) {
                        //當(dāng)前值賦值c后,遞歸調(diào)用全部滿足數(shù)獨(dú)矩陣合法性匾灶,
                        //則返回成功
                        return true;
                    }
                    //當(dāng)前位置放入c后棱烂,后續(xù)位置不能得到合法的數(shù)獨(dú)矩陣,
                    //繼續(xù)進(jìn)行回溯分析阶女,因?yàn)樯洗螌舆f歸調(diào)用要重寫(xiě)開(kāi)始分析颊糜,
                    //所以要恢復(fù)當(dāng)前的原始值
                    board[y][x] = '.';
                }
                //'1'~'9'全部試探完成后,
                //依然無(wú)法獲得合法數(shù)獨(dú)矩陣秃踩,
                //則說(shuō)明之前放入的值有誤衬鱼,
                //返回后上次層遞歸方法繼續(xù)取其他值進(jìn)行遞歸
                return false;
            }
            //下一行,從第一列開(kāi)始
            x = 0;
        }
        //此時(shí)數(shù)組已經(jīng)越界吞瞪,
        //說(shuō)明全部遞歸完成沒(méi)有發(fā)現(xiàn)非法數(shù)獨(dú)矩陣馁启,返回成功
        return true;
    }

驗(yàn)證

最后完成測(cè)試用例以及調(diào)用方法,進(jìn)行結(jié)果驗(yàn)證:

    public void solveSudoku(char[][] board) {
        check(board, 0, 0);
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        char[][] board = {
                {'5', '3', '.', '.', '7', '.', '.', '.', '.'},
                {'6', '.', '.', '1', '9', '5', '.', '.', '.'},
                {'.', '9', '8', '.', '.', '.', '.', '6', '.'},
                {'8', '.', '.', '.', '6', '.', '.', '.', '3'},
                {'4', '.', '.', '8', '.', '3', '.', '.', '1'},
                {'7', '.', '.', '.', '2', '.', '.', '.', '6'},
                {'.', '6', '.', '.', '.', '.', '2', '8', '.'},
                {'.', '.', '.', '4', '1', '9', '.', '.', '5'},
                {'.', '.', '.', '.', '8', '.', '.', '7', '9'}
        };
        solution.solveSudoku(board);
        System.out.println("{");
        for (char[] row : board) {
            System.out.print("    {");
            String split = "";
            for (char c : row) {
                System.out.print(split + c);
                split = ",";
            }
            System.out.println("},");
        }
        System.out.println("}");
    }

得到正確結(jié)果:

{
    {5,3,4,6,7,8,9,1,2},
    {6,7,2,1,9,5,3,4,8},
    {1,9,8,3,4,2,5,6,7},
    {8,5,9,7,6,1,4,2,3},
    {4,2,6,8,5,3,7,9,1},
    {7,1,3,9,2,4,8,5,6},
    {9,6,1,5,3,7,2,8,4},
    {2,8,7,4,1,9,6,3,5},
    {3,4,5,2,8,6,1,7,9},
}

好了芍秆,以后這種數(shù)獨(dú)問(wèn)題我們都能在幾毫秒內(nèi)解決它了:)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惯疙,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子妖啥,更是在濱河造成了極大的恐慌霉颠,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荆虱,死亡現(xiàn)場(chǎng)離奇詭異蒿偎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)怀读,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門诉位,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人菜枷,你說(shuō)我怎么就攤上這事苍糠。” “怎么了啤誊?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵岳瞭,是天一觀的道長(zhǎng)拥娄。 經(jīng)常有香客問(wèn)我,道長(zhǎng)瞳筏,這世上最難降的妖魔是什么稚瘾? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮姚炕,結(jié)果婚禮上摊欠,老公的妹妹穿的比我還像新娘。我一直安慰自己柱宦,他們只是感情好凄硼,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著捷沸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狐史。 梳的紋絲不亂的頭發(fā)上痒给,一...
    開(kāi)封第一講書(shū)人閱讀 49,749評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音骏全,去河邊找鬼苍柏。 笑死,一個(gè)胖子當(dāng)著我的面吹牛姜贡,可吹牛的內(nèi)容都是我干的试吁。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼楼咳,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼熄捍!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起母怜,我...
    開(kāi)封第一講書(shū)人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤余耽,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后苹熏,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體碟贾,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年轨域,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了袱耽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡干发,死狀恐怖朱巨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情铐然,我是刑警寧澤蔬崩,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布恶座,位于F島的核電站,受9級(jí)特大地震影響沥阳,放射性物質(zhì)發(fā)生泄漏跨琳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一桐罕、第九天 我趴在偏房一處隱蔽的房頂上張望脉让。 院中可真熱鬧,春花似錦功炮、人聲如沸溅潜。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)滚澜。三九已至,卻和暖如春嫁怀,著一層夾襖步出監(jiān)牢的瞬間设捐,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工塘淑, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留萝招,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓存捺,卻偏偏與公主長(zhǎng)得像槐沼,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捌治,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 在C語(yǔ)言中,五種基本數(shù)據(jù)類型存儲(chǔ)空間長(zhǎng)度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來(lái)閱讀 3,333評(píng)論 0 2
  • 簡(jiǎn)述 極客時(shí)間算法40講中所出現(xiàn)的leetcode算法題 題目 【鏈表】reverse-linked-list(反...
    BestbpF閱讀 4,468評(píng)論 0 4
  • 數(shù)獨(dú)起源于18世紀(jì)初瑞士數(shù)學(xué)家歐拉等人研究的拉丁方陣岗钩,20世紀(jì)70年代,經(jīng)過(guò)美國(guó)及日本學(xué)者的推廣和改良具滴,定名為數(shù)獨(dú)...
    放翁lcf閱讀 928評(píng)論 0 1
  • 項(xiàng)目的源代碼在Github上托管凹嘲,可以在這里查看。 PSP表格 思路 項(xiàng)目要求的程序主要需要實(shí)現(xiàn)兩個(gè)功能: 求解數(shù)...
    系欲雨清閱讀 1,403評(píng)論 0 2
  • 在寫(xiě)11月份的計(jì)劃,順手回顧了一下10月份的記錄疲恢⌒桌剩看完后,長(zhǎng)吁一口氣显拳,原來(lái)人真的可以做很多事棚愤,而這些事在一個(gè)月之前...
    貓狼社長(zhǎng)閱讀 378評(píng)論 0 2