From ff96d8cc0801074b93a2a15e0da9161bd68a11b4 Mon Sep 17 00:00:00 2001 From: haiker2011 Date: Sun, 30 Sep 2018 21:31:15 +0800 Subject: [PATCH] add #13 #14 --- notes/面试总结.md | 111 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/notes/面试总结.md b/notes/面试总结.md index 439ea927..06298c75 100644 --- a/notes/面试总结.md +++ b/notes/面试总结.md @@ -14,6 +14,8 @@ * [10.4 变态跳台阶](#104-变态跳台阶) * [11. 旋转数组的最小数字](#11-旋转数组的最小数字) * [12. 矩阵中的路径](#12-矩阵中的路径) +* [13. 机器人的运动范围](#13-机器人的运动范围) +* [14. 剪绳子](#14-剪绳子) * [参考文献](#参考文献) @@ -957,6 +959,115 @@ class Solution: idx += 1 return array ``` +# 13. 机器人的运动范围 + +[NowCoder](https://www.nowcoder.com/practice/6e5207314b5241fb83f2329e89fdecc8?tpId=13&tqId=11219&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking) + +## 题目描述 + +地上有一个 m 行和 n 列的方格。一个机器人从坐标 (0, 0) 的格子开始移动,每一次只能向左右上下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于 k 的格子。 + +例如,当 k 为 18 时,机器人能够进入方格 (35,37),因为 3+5+3+7=18。但是,它不能进入方格 (35,37),因为 3+5+3+8=19。请问该机器人能够达到多少个格子? + +## 解题思路 + +```java +private static final int[][] next = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; +private int cnt = 0; +private int rows; +private int cols; +private int threshold; +private int[][] digitSum; + +public int movingCount(int threshold, int rows, int cols) { + this.rows = rows; + this.cols = cols; + this.threshold = threshold; + initDigitSum(); + boolean[][] marked = new boolean[rows][cols]; + dfs(marked, 0, 0); + return cnt; +} + +private void dfs(boolean[][] marked, int r, int c) { + if (r < 0 || r >= rows || c < 0 || c >= cols || marked[r][c]) + return; + marked[r][c] = true; + if (this.digitSum[r][c] > this.threshold) + return; + cnt++; + for (int[] n : next) + dfs(marked, r + n[0], c + n[1]); +} + +private void initDigitSum() { + int[] digitSumOne = new int[Math.max(rows, cols)]; + for (int i = 0; i < digitSumOne.length; i++) { + int n = i; + while (n > 0) { + digitSumOne[i] += n % 10; + n /= 10; + } + } + this.digitSum = new int[rows][cols]; + for (int i = 0; i < this.rows; i++) + for (int j = 0; j < this.cols; j++) + this.digitSum[i][j] = digitSumOne[i] + digitSumOne[j]; +} +``` + +# 14. 剪绳子 + +[Leetcode](https://leetcode.com/problems/integer-break/description/) + +## 题目描述 + +把一根绳子剪成多段,并且使得每段的长度乘积最大。 + +```html +n = 2 +return 1 (2 = 1 + 1) + +n = 10 +return 36 (10 = 3 + 3 + 4) +``` + +## 解题思路 + +### 贪心 + +尽可能多剪长度为 3 的绳子,并且不允许有长度为 1 的绳子出现。如果出现了,就从已经切好长度为 3 的绳子中拿出一段与长度为 1 的绳子重新组合,把它们切成两段长度为 2 的绳子。 + +证明:当 n >= 5 时,3(n - 3) - 2(n - 2) = n - 5 >= 0。因此把长度大于 5 的绳子切成两段,令其中一段长度为 3 可以使得两段的乘积最大。 + +```java +public int integerBreak(int n) { + if (n < 2) + return 0; + if (n == 2) + return 1; + if (n == 3) + return 2; + int timesOf3 = n / 3; + if (n - timesOf3 * 3 == 1) + timesOf3--; + int timesOf2 = (n - timesOf3 * 3) / 2; + return (int) (Math.pow(3, timesOf3)) * (int) (Math.pow(2, timesOf2)); +} +``` + +### 动态规划 + +```java +public int integerBreak(int n) { + int[] dp = new int[n + 1]; + dp[1] = 1; + for (int i = 2; i <= n; i++) + for (int j = 1; j < i; j++) + dp[i] = Math.max(dp[i], Math.max(j * (i - j), dp[j] * (i - j))); + return dp[n]; +} +``` # 参考文献