ソードフィンガーオファー第2版
13. ロボットの可動範囲
タイトル: 座標 [0,0] から座標 [m-1,n-1] までの m 行 n 列の正方形が地面にあります。ロボットは座標 [0, 0] のグリッドから移動を開始し、そのたびに上下左右に 1 つのグリッドを移動できます (グリッドの外に移動することはできません)。 k グリッドより大きい行座標と列座標の桁。たとえば、k が 18 の場合、3+5+3+7=18 であるため、ロボットは正方形 [35, 37] に入ることができます。ただし、3+5+3+8=19 であるため、正方形 [35, 38] には入れません。ロボットはいくつのグリッドに到達できますか?
例 1:
入力: m = 2、n = 3、k = 1
出力: 3
class Solution {
boolean[][] visited; // 存储每个格子是否被访问过
int res = 0; // 记录可到达的格子数
int m; // 行数
int n; // 列数
public int movingCount(int m, int n, int k) {
if (m == 0) {
// 如果行数为0,返回0
return 0;
}
this.m = m;
this.n = n;
visited = new boolean[m][n]; // 初始化visited数组
dfs(0, 0, k); // 从(0, 0)开始dfs搜索
return res; // 返回可到达的格子数
}
private void dfs(int i, int j, int k) {
if (i < 0 || j < 0 || i >= m || j >= n || check(i, j, k) || visited[i][j]) {
// 如果i或j越界、格子的数字和大于k、或者格子已经被访问过,返回
return;
}
res++; // 可到达的格子数加1
visited[i][j] = true; // 标记格子(i, j)已经被访问过
dfs(i + 1, j, k); // 向下搜索
dfs(i - 1, j, k); // 向上搜索
dfs(i, j + 1, k); // 向右搜索
dfs(i, j - 1, k); // 向左搜索
//不能回头
//visited[i][j] = false;
}
private boolean check(int i, int j, int k) {
// 判断格子(i, j)的数字和是否大于k
int res = 0;
while (i != 0) {
res += i % 10;
i /= 10;
}
while (j != 0) {
res += j % 10;
j /= 10;
}
if (res > k) {
return true;
} else {
return false;
}
}
}
19. 正規表現マッチング
タイトル: 「.」と「 」を含む正規表現を照合する機能を実装してください。パターン内の文字「.」は任意の文字を意味し、「」は前の文字が何度でも (0 回を含む) 出現できることを意味します。この質問では、一致とは、文字列のすべての文字がパターン全体に一致することを意味します。たとえば、文字列「aaa」はパターン「aa」および「ab ac a」に一致しますが、「aa.a」または「ab*a」には一致しません。
例 1:
入力:
s = "aa"
p = "a"
出力: false
説明: "a" は "aa" の文字列全体と一致することはできません。
class Solution {
public boolean isMatch(String s, String p) {
// 获取字符串s和p的长度。
int m = s.length();
int n = p.length();
// 创建一个二维布尔数组来存储子问题的结果。
boolean[][] dp = new boolean[m + 1][n + 1];
// 设置第一个元素的初始值为true。
dp[0][0] = true;
// 当p为空时,设置第一行的初始值。
for (int i = 2; i <= p.length(); i++) {
if (p.charAt(i - 1) == '*') {
dp[0][i] = dp[0][i - 2];
}
}
// 遍历整个dp数组,并根据递推关系填充它。
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// 如果p中的当前字符不是'*',我们需要检查s和p中的当前字符是否匹配。
if (p.charAt(j - 1) != '*') {
if (p.charAt(j - 1) == s.charAt(i - 1) || p.charAt(j - 1) == '.') {
dp[i][j] = dp[i - 1][j - 1];
}
} // 如果p中的当前字符是'*',有两种情况需要考虑。
else {
// 如果p中的前一个字符不匹配s中的当前字符且不是'.',则可以跳过p中的最后两个字符。
if (p.charAt(j - 2) != s.charAt(i - 1) && p.charAt(j - 2) != '.') {
dp[i][j] = dp[i][j - 2];
} // 如果p中的前一个字符匹配s中的当前字符或是'.',则有三种可能的情况需要考虑。
else {
dp[i][j] = dp[i][j - 1] || dp[i][j - 2] || dp[i - 1][j];
}
}
}
}
// 返回最后一个子问题的结果。
return dp[m][n];
}
}
20. 数値を表す文字列
質問: 文字列が値 (整数と小数を含む) を表すかどうかを判断する関数を実装してください。
値 (順番) は次の部分に分割できます:
スペース
10 進数または整数
(オプション) 'e' または 'E' の後に整数が続きます
スペース
10 進数 (順番) は次の部分に分割できます:
(オプション)
次のいずれかの形式の符号文字 (「+」または「-」) :
少なくとも 1 つの数字の後にピリオド「.」が続く
少なくとも 1 つの数字の後にピリオド「.」が続き、少なくとも 1 つの数字が
続くドット「.」の後に少なくとも 1 桁の数字が続く 整数
(順序どおり) は、次の部分に分割できます:
(オプション) 符号文字 (「+」または「-」)
少なくとも 1 つの数字
部分 値の列挙 次のように:
[ 「+100」、「5e2」、「-123」、「3.1416」、「-1E-16」、「0123」]
いくつかの非値は次のようにリストされています:
[「12e」、「1a3.14」 , “ 1.2.3", "±5", "12e+5.4"]
例 1:
入力: s = "0"
出力: true
アイデア分析: 3 つのブール変数 isNum、isDot、isE を使用して、文字列に数字、小数点、指数記号があるかどうかを記録します。具体的には、文字にトラバースする場合、それが数値の場合は isNum を true に設定し、それが小数点であり、小数点と指数記号が以前に出現していない場合は isDot を true に設定し、指数記号の場合は isDot を true に設定します。数値が前にあり、指数記号がない場合は、isE を true に、isNum を false に設定します; プラス記号またはマイナス記号の場合は、文字列の先頭または指数記号の直後に表示する必要があります; 次の場合は false を返しますは、数値、小数点、指数記号、正符号または負符号ではありません。最後に、文字列に数字があるかどうかを示す isNum の値を返します。
時間計算量: O ( n ) O(n)O(n),其中 n n アルゴリズムは文字列内の各文字を反復処理する必要があるため、 nは文字列の長さです。
スペースの複雑さ:O ( 1 ) O(1)O ( 1 )は、アルゴリズムが 3 つのブール変数を格納するために一定量の余分なスペースのみを使用するためです。
class Solution {
public boolean isNumber(String s) {
// 去除字符串两端的空格。
s = s.trim();
// 如果字符串为空或长度为0,则返回false。
if (s == null || s.length() == 0) {
return false;
}
// 初始化三个布尔变量,用于记录字符串中是否有数字、小数点和指数符号。
boolean isNum = false;
boolean isDot = false;
boolean isE = false;
// 遍历字符串中的每个字符。
for (int i = 0; i < s.length(); i++) {
// 如果当前字符是数字,则将isNum设置为true。
if (Character.isDigit(s.charAt(i))) {
isNum = true;
} // 如果当前字符是小数点,并且之前没有出现过小数点和指数符号,则将isDot设置为true。
else if (s.charAt(i) == '.' && !isDot && !isE) {
isDot = true;
} // 如果当前字符是指数符号,并且之前出现过数字但没有出现过指数符号,则将isE设置为true,并将isNum设置为false(因为指数符号的出现意味着当前数字已经结束了)。
else if ((s.charAt(i) == 'e' || s.charAt(i) == 'E') && isNum && !isE) {
isE = true;
isNum = false;
} // 如果当前字符是加号或减号,则它必须出现在字符串的开头或紧接着指数符号之后。
else if (s.charAt(i) == '+' || s.charAt(i) == '-') {
if (i != 0 && s.charAt(i - 1) != 'e' && s.charAt(i - 1) != 'E') {
return false;
}
} // 如果当前字符不是数字、小数点、指数符号或加减号,则返回false。
else {
return false;
}
}
// 返回isNum的值,表示字符串中是否有数字。
return isNum;
}
}