1. 程式人生 > >【劍指Offer學習】【面試題66:矩陣中的路徑】

【劍指Offer學習】【面試題66:矩陣中的路徑】

題目:請設計一個函式,用來判斷在一個矩陣中是否存在一條包含某字串所有字元的路徑。路徑可以從矩陣中任意一格開始,每一步可以在矩陣中間向左、右、上、下移動一格。如果一條路徑經過了矩陣的某一格,那麼該路徑不能再次進入該格子。

舉例分析

  例如在下面的3*4的矩陣中包含一條字串”bcced”的路徑。但矩陣中不包含字串“abcb”的路徑,因為字串的第一個字元b佔據了矩陣中的第一行第二格子之後,路徑不能再次進入這個格子。
a b c e
s f c s
a d e e

解題思路

  這是一個可以用回朔法解決的典型題。首先,在矩陣中任選一個格子作為路徑的起點。假設矩陣中某個格子的字元為ch,那麼這個格子不可能處在路徑上的第i個位置。如果路徑上的第i個字元不是ch,那麼這個格子不可能處在路徑上的第i個位置。如果路徑上的第i個字元正好是ch,那麼往相鄰的格子尋找路徑上的第i+1個字元。除在矩陣邊界上的格子之外,其他格子都有4個相鄰的格子。重複這個過程知道路徑上的所有字元都在矩陣中找到相應的位置。
  由於回朔法的遞迴特性,路徑可以被開成一個棧。當在矩陣中定位了路徑中前n個字元的位置之後,在與第n個字元對應的格子的周圍都沒有找到第n+1個字元,這個時候只要在路徑上回到第n-1個字元,重新定位第n個字元。
  由於路徑不能重複進入矩陣的格子,還需要定義和字元矩陣大小一樣的布林值矩陣,用來標識路徑是否已經進入每個格子。
當矩陣中座標為(row,col)的格子和路徑字串中下標為pathLength的字元一樣時,從4個相鄰的格子(row,col-1),(row-1,col),(row,col+1)以及(row+1,col)中去定位路徑字串中下標為pathLength+1的字元。
  如果4個相鄰的格子都沒有匹配字串中下標為pathLength+1的字元,表明當前路徑字串中下標為pathLength的字元在矩陣中的定位不正確,我們需要回到前一個字元(pathLength-1),然後重新定位。
  一直重複這個過程,直到路徑字串上所有字元都在矩陣中找到合適的位置

程式碼實現

public class Test66 {
    /**
     * 題目:請設計一個函式,用來判斷在一個矩陣中是否存在一條包含某字串所有字元的路徑。
     * 路徑可以從矩陣中任意一格開始,每一步可以在矩陣中間向左、右、上、下移動一格。
     * 如果一條路徑經過了矩陣的某一格,那麼該路徑不能再次進入該格子。
     *
     * @param matrix 輸入矩陣
     * @param rows   矩陣行數
     * @param cols   矩陣列數
     * @param str    要搜尋的字串
     * @return
是否找到 true是,false否 */
public static boolean hasPath(char[] matrix, int rows, int cols, char[] str) { // 引數校驗 if (matrix == null || matrix.length != rows * cols || str == null || str.length < 1) { return false; } // 變數初始化 boolean[] visited = new
boolean[rows * cols]; for (int i = 0; i < visited.length; i++) { visited[i] = false; } // 記錄結果的陣列, int[] pathLength = {0}; // 以每一個點為起始進行搜尋 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (hasPathCore(matrix, rows, cols, str, visited, i, j, pathLength)) { return true; } } } return false; } /** * 回溯搜尋演算法 * * @param matrix 輸入矩陣 * @param rows 矩陣行數 * @param cols 矩陣列數 * @param str 要搜尋的字串 * @param visited 訪問標記陣列 * @param row 當前處理的行號 * @param col 當前處理的列號 * @param pathLength 已經處理的str中字元個數 * @return 是否找到 true是,false否 */ private static boolean hasPathCore(char[] matrix, int rows, int cols, char[] str, boolean[] visited, int row, int col, int[] pathLength) { if (pathLength[0] == str.length) { return true; } boolean hasPath = false; // 判斷位置是否合法 if (row >= 0 && row < rows && col >= 0 && col < cols && matrix[row * cols + col] == str[pathLength[0]] && !visited[row * cols + col]) { visited[row * cols + col] = true; pathLength[0]++; // 按左上右下進行回溯 hasPath = hasPathCore(matrix, rows, cols, str, visited, row, col - 1, pathLength) || hasPathCore(matrix, rows, cols, str, visited, row - 1, col, pathLength) || hasPathCore(matrix, rows, cols, str, visited, row, col + 1, pathLength) || hasPathCore(matrix, rows, cols, str, visited, row + 1, col, pathLength); if (!hasPath) { pathLength[0]--; visited[row * cols + col] = false; } } return hasPath; } public static void main(String[] args) { //ABCE //ABCCED //SFCS //ADEE System.out.println(hasPath("ABCESFCSADEE".toCharArray(), 3, 4, "ABCCED".toCharArray()) + "[true]");// true //ABCE //SEE //SFCS //ADEE System.out.println(hasPath("ABCESFCSADEE".toCharArray(), 3, 4, "SEE".toCharArray()) + "[true]");// true //ABCE //ABCB //SFCS //ADEE System.out.println(hasPath("ABCESFCSADEE".toCharArray(), 3, 4, "ABCB".toCharArray()) + "[false]");// false //ABCEHJIG //SLHECCEIDEJFGGFIE //SFCSLOPQ //ADEEMNOE //ADIDEJFM //VCEIFGGS System.out.println(hasPath("ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS".toCharArray(), 5, 8, "SLHECCEIDEJFGGFIE".toCharArray()) + "[true]");// true //ABCEHJIG //SGGFIECVAASABCEHJIGQEM //SFCSLOPQ // //ADEEMNOE //ADIDEJFM //VCEIFGGS System.out.println(hasPath("ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS".toCharArray(), 5, 8, "SGGFIECVAASABCEHJIGQEM".toCharArray()) + "[true]");// true //ABCEHJIG //SGGFIECVAASABCEEJIGOEM //SFCSLOPQ //ADEEMNOE //ADIDEJFM //VCEIFGGS System.out.println(hasPath("ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS".toCharArray(), 5, 8, "SGGFIECVAASABCEEJIGOEM".toCharArray()) + "[false]");// false //ABCEHJIG //SGGFIECVAASABCEHJIGQEMS //SFCSLOPQ //ADEEMNOE //ADIDEJFM //VCEIFGGS System.out.println(hasPath("ABCEHJIGSFCSLOPQADEEMNOEADIDEJFMVCEIFGGS".toCharArray(), 5, 8, "SGGFIECVAASABCEHJIGQEMS".toCharArray()) + "[false]");// false //AAAA //AAAAAAAAAAAA //AAAA //AAAA System.out.println(hasPath("AAAAAAAAAAAA".toCharArray(), 3, 4, "AAAAAAAAAAAA".toCharArray()) + "[true]");// true //AAAA //AAAAAAAAAAAAA //AAAA //AAAA System.out.println(hasPath("AAAAAAAAAAAA".toCharArray(), 3, 4, "AAAAAAAAAAAAA".toCharArray()) + "[false]");// false } }

執行結果

這裡寫圖片描述

特別說明

相關推薦

Offer學習試題66矩陣路徑

題目:請設計一個函式,用來判斷在一個矩陣中是否存在一條包含某字串所有字元的路徑。路徑可以從矩陣中任意一格開始,每一步可以在矩陣中間向左、右、上、下移動一格。如果一條路徑經過了矩陣的某一格,那麼該路徑不能再次進入該格子。 舉例分析   例如在下面的3*

Offer試題66矩陣路徑 java實現

/************************************************************** * Copyright (c) 2016, * All rights reserved. * 版 本 號:v1.0

Offer學習所有試題匯總

tails 超過一半 奇數 正則表達式 detail 刪除 祖先 滑動窗口 翻轉單詞順序 劍指Offer學習   劍指Offer這本書已經學習完了,從中也學習到了不少的東西,現在做一個總的目錄,供自已和大家一起參考,學如逆水行舟,不進則退。只有不斷地學習才能跟上時候,跟得

Offer學習試題5 從尾到頭列印連結串列思路

方案一:(後進先出)遍歷連結串列,再從棧頂開始出個輸出結點的值,此時輸出的結點的順序已經反轉過來了。 先推進棧 再依次取出棧頂元素 方案二:遞迴。 判斷連結串列頭結點是否為空 將 next 結點作為下一次的實參 輸出當前棧頂元素。 缺點:當連結串

Offer學習所有試題彙總

劍指Offer學習   劍指Offer這本書已經學習完了,從中也學習到了不少的東西,現在做一個總的目錄,供自已和大家一起參考,學如逆水行舟,不進則退。只有不斷地學習才能跟上時候,跟得上技術的潮流! 目錄 第01-10題 第11-20題 第21-30題

Offer學習試題4 替換空格思路

題目: 請實現一個函式,將一個字串中的每個空格替換成“%20”。例如,當字串為We Are Happy,則經過替換之後的字串為We%20Are%20Happy。 思路: 遍歷的方向兩邊皆可。 若從後往前遍歷,新的字串需要反轉。 用 String 類的方法判斷字串

Offer學習試題5 從尾到頭列印連結串列

題目:輸入個連結串列的頭結點,從尾到頭反過來打印出每個結點的值。 public class Test05 { /** * 結點物件 */ public s

Offer學習試題26複雜連結串列的複製

題目:請實現函式ComplexListNode clone(ComplexListNode head),複製一個複雜連結串列。在複雜連結串列中,每個結點除了有一個next 域指向下一個結點外,還有一個sibling 指向連結串列中的任意結點或者null。

Offer學習試題56連結串列中環的入口結點

題目:一個連結串列中包含環,如何找出環的入口結點? 解題思路   可以用兩個指標來解決這個問題。先定義兩個指標P1和P2指向連結串列的頭結點。如果連結串列中環有n個結點,指標P1在連結串列上向前移動n步,然後兩個指標以相同的速度向前移動。當第二個指標

Offer學習試題60把二叉樹打印出多行

題目:從上到下按層列印二叉樹,同一層的結點按從左到右的順序列印,每一層列印一行。 解題思路   用一個佇列來儲存將要列印的結點。為了把二叉樹的每一行單獨列印到一行裡,我們需要兩個變數:一個變量表示在當前的層中還沒有列印的結點數,另一個變量表示下一次結

Offer學習試題50兩個結點的最低公共祖先

題目:求樹中兩個結點的最低公共祖先,此樹不是二叉樹,並且沒有指向父節點的指標。 樹的結點定義 private static class TreeNode { int val; List<TreeNode> childre

Offer學習試題67機器人的運動範圍

題目:地上有個m行n列的方格。一個機器人從座標(0,0)的格子開始移動,它每一次可以向左、右、上、下移動一格,但不能進入行座標和列座標的數位之和大於k的格子。 舉例分析   例如,當k為18時,機器人能夠進入方格(35,37),因為3+5+3+7=1

Offer學習試題31連續子陣列的最大和

題目:輸入一個整型陣列,數組裡有正數也有負數。陣列中一個或連續的多個整陣列成一個子陣列。求所有子陣列的和的最大值。要求時間複雜度為O(n)。 例子說明: 例如輸入的陣列為{1, -2, 3, 10, -4, 7, 2, -5},和最大的子陣列為{3,

Offer學習試題54表示數值的字串

題目:請實現一個函式用來判斷字串是否表示數值(包括整數和小數)。 例子說明   例如,字串“+100”,“5e2”,“-123”,“3.1416”及”-1E-16”都表示數值,但“12e”,”1a3.14”,”1.2.3”,”+-5”及“12e+5.

Offer學習試題18 樹的子結構

題目:輸入兩棵二叉樹A 和B,判斷B 是不是A 的子結構。 二叉樹結點的定義: /** * 二叉樹的樹結點 */ public static class BinaryTreeNode { int value; BinaryT

Offer學習試題13 在O(1)時間刪除連結串列結點

程式碼實現: public class Test13 { /** * 連結串列結點 */ public static class ListNode { int value; // 儲存連結串列的值 L

Offer學習試題11 數值的整數次方

程式碼實現: public class Test11 { /** * 實現函式double Power(double base, int exponent),求base的exponent次方。 * 不得使用庫函式,同時不需要考慮大數問題。

Offer學習試題36陣列的逆序對

題目:在陣列中的兩個數字如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個陣列中的逆序對的總數。 舉例分析   例如在陣列{7, 5, 6, 4 中, 一共存在5 個逆序對,分別是(7, 6)、(7,5),(7, 4)

Offer學習試題28 字串的排列

題目:輸入一個字串,打印出該字串中字元的所有排列。例如輸入字串abc。則打印出由字元a、b、c 所能排列出來的所有字串abc、acb、bac 、bca、cab 和cba 。 解題思路: 把一個字串看成由兩部分組成:第一部分為它的第一個字元,第二部分是後面

Offer學習試題14 調整陣列順序使奇數位於偶數前面

題目:輸入一個整數陣列,實現一個函式來調整該陣列中數字的順序,使得所有奇數位於陣列的前半部分,所有偶數位予陣列的後半部分。 這個題目要求把奇數放在陣列的前半部分, 偶數放在陣列的後半部分,因此所有的奇數應該位於偶數的前面。也就是說我們在掃描這個陣列的時候, 如