f ( 0 ) = 0 ; f ( 1 ) = 1 ; f ( n ) = f ( n − 1 ) + f ( n − 2 ) , n > = 2 f(0)=0;f(1)=1;f(n)=f(n-1)+f(n-2),n>=2 f(0)=0;f(1)=1;f(n)=f(n−1)+f(n−2),n>=2
983ms
。public int Fibonacci(int n){
if (n <= 1) {
return n;
}
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
public static int Fibonacci(int n) {
// n=0,要单独处理
if (n == 0) {
return 0;
}
int[] dp = new int[n + 1];
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
12ms
。public static int Fibonacci(int n) {
// 对n<=1进行单独处理
if (n <= 1) {
return n;
}
int f0 = 0, f1 = 1;
int fn = 0;
for (int i = 2; i <= n; i++) {
fn = f0 + f1;
f0 = f1;
f1 = fn;
}
return fn;
}
n > 2
时,第一次可以跳1级,则总共的跳法是后面n - 1
级的跳法;第一次跳2级,则总共的跳法是后面n - 2
级的跳法。所以,总的跳法为 f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n)=f(n-1)+f(n-2) f(n)=f(n−1)+f(n−2),其中 f ( 0 ) = 0 , f ( 1 ) = 1 , f ( 2 ) = 2 f(0)=0,f(1)=1,f(2)=2 f(0)=0,f(1)=1,f(2)=2。2 x 8
区域的覆盖方法记为 f ( 8 ) f(8) f(8)。2 x 1
的矩形竖着放,则还剩下2 x 7
的区域可以放置,我们 f ( 7 ) f(7) f(7)。2 x 1
的矩形横着放,则其下方必须横着再放一个2 x 1
的矩形,还剩下2 x 6
的区域需要放置,记为 f ( 6 ) f(6) f(6)。n = 3
开始,才能使用 f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n)=f(n-1)+f(n-2) f(n)=f(n−1)+f(n−2)。public int RectCover(int target) {
if (target <= 2) {
return target;
}
int a = 1, b = 2, c = 0;
for (int i = 3; i <= target; i++) {
c = a + b;
a = b;
b = c;
}
return c;
}
public int JumpFloorII(int target) {
int[] dp = new int[target];
Arrays.fill(dp, 1);
for (int i = 1; i < target; i++) {
for (int j = 0; j < i; j++) {
dp[i] = dp[i] + dp[j];
}
}
return dp[target - 1];
}
nums[mid] <= nums[end]
,说明最小值应该在start和mid之间;否则,最小值应该在mid+1和end之间。nums[start] == nums[mid] == nums[end]
的情况,如 {1,1,1,0,1}
。此时无法判断最小处于哪个部分,需要切换到顺序查找。只需要查找目前的start到end之间min即可。public int minNumberInRotateArray(int[] array) {
if (array.length == 0) {
return 0;
}
int start = 0, end = array.length - 1;
while (start < end) {
int mid = start + (end - start) / 2;
if (array[start] == array[mid] && array[mid] == array[end]) {
return findOnebyOne(array, start, end);
} else if (array[mid] <= array[end]) {
end = mid;
} else {
start = mid + 1;
}
}
return array[start];
}
public int findOnebyOne(int[] array, int start, int end) {
int min = array[start];
for (int i = start + 1; i <= end; i++) {
if (min > array[i]) {
min = array[i];
}
}
return min;
}
nums[mid]=target
,说明找到了;nums[start] <= nums[mid]
,则可能左半段有序,在左半段中确定start或者end的位置;start <= end
;因为这个条件,所以无需对数组长度为0的情况进行处理。public int search(int[] nums, int target) {
int start = 0, end = nums.length - 1;
while (start <= end) {
int mid = (start + end) / 2;
if (nums[mid] == target) {
return mid;
}
if (nums[start] <= nums[mid]) {// 左半段有序
if (target >= nums[start] && target < nums[mid]) {// 目标值在左半段
end = mid - 1;
} else {// 目标值在右半段
start = mid + 1;
}
} else {// 右半段有序
if (target > nums[mid] && target <= nums[end]) {// 目标值在右半段
start = mid + 1;
} else {// 目标值在左半段
end = mid - 1;
}
}
}
return -1;
}
start <= end
,就执行对nums[mid]
的判断。如果没有找到,则更新start或end,继续查找。public int search(int[] nums, int target) {
int start = 0, end = nums.length - 1;
return binarySearch(nums, target, start, end);
}
public int binarySearch(int[] nums, int target, int start, int end) {
if (start <= end) {
int mid = start + (end - start) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
return binarySearch(nums, target, mid + 1, end);
} else {
return binarySearch(nums, target, start, mid - 1);
}
}
return -1;
}
public int search(int[] nums, int target) {
int start = 0, end = nums.length - 1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (nums[mid] == target) {
return mid;
} else if (nums[mid] < target) {
start = mid + 1;
} else {
end = mid - 1;
}
}
return -1;
}
visited
数组记录哪些位置被访问过,如果当前位置被选中,则值为true,继续回溯相邻的位置;如果当前位置不可行,需要将其标记为false,回到上一个位置。private int row;
private int col;
private boolean[][] visited;
public boolean exist(char[][] board, String word) {
row = board.length;
col = board[0].length;
visited = new boolean[row][col];
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
// 当前字符与首字符匹配,栋当前位置开始,查找是否存在可行路径
if (board[i][j] == word.charAt(0) && backtrace(board, word, 0, i, j)) {
return true;
}
}
}
return false;
}
public boolean backtrace(char[][] board, String word, int curIndex, int i, int j) {
if (curIndex == word.length()) {
return true;
}
// 如果i,j超出矩阵,或者当前位置已经被访问过,
// 或者当前位置的字符与待查找的字符不匹配,停止查找
if (i < 0 || i >= row || j < 0 || j >= col ||
visited[i][j] || board[i][j] != word.charAt(curIndex)) {
return false;
}
// 先标记当前位置已经访问过
visited[i][j] = true;
// 从当前位置开始朝四周查找下一个字符,只要有一个路径可行,则当前位置可行
if (backtrace(board, word, curIndex + 1, i - 1, j) ||
backtrace(board, word, curIndex + 1, i + 1, j) ||
backtrace(board, word, curIndex + 1, i, j - 1) ||
backtrace(board, word, curIndex + 1, i, j + 1)) {
return true;
}
// 当前位置不可行,需要回溯,更改visited
visited[i][j] = false;
return false;
}
0 ~ max(row, col)
的数位之和,行列之和直接从里面取值相加即可。private int[][] direct = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
private int[][] matrix;
private boolean[][] visited;
private int count = 0;
public int movingCount(int threshold, int rows, int cols) {
// 只需要计算行列中的最大值即可,避免重复计算
int[] sum = new int[Math.max(rows, cols)];
matrix = new int[rows][cols];
visited = new boolean[rows][cols];
// 先计算每个格子的数位之和
computeTotalSum(sum);
// 初始化矩阵,矩阵中的值为row和col的数位之和
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = sum[i] + sum[j];
}
}
// 深度优先搜索整个矩阵
dfs(matrix, 0, 0, threshold);
return count;
}
public void dfs(int[][] matrix, int i, int j, int threshold) {
// 超出矩阵边界,当前格子已经被访问过,超出阈值
if (i < 0 || i >= matrix.length || j < 0 || j >= matrix[0].length ||
visited[i][j] || matrix[i][j] > threshold) {
return;
}
// 当前格子满足条件,计数变量加1
visited[i][j] = true;
count++;
for (int d = 0; d < 4; d++) {
dfs(matrix, i + direct[d][0], j + direct[d][1], threshold);
}
}
public void computeTotalSum(int[] sum) {
for (int i = 0; i < sum.length; i++) {
sum[i] = helper(i);
}
}
public int helper(int num) {
int sum = 0;
while (num != 0) {
sum += num % 10;
num = num / 10;
}
return sum;
}
grid[0].length
无法获取。public int numIslands(char[][] grid) {
// 特殊情况,如果矩阵为为空,直接返回0
if (grid.length==0||grid[0].length==0){
return 0;
}
int row = grid.length, col = grid[0].length;
boolean[][] visited = new boolean[row][col];
int count = 0;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (grid[i][j] == '1' && !visited[i][j]) {
count++;
DFS(grid, i, j, visited);
}
}
}
return count;
}
public void DFS(char[][] grid, int i, int j, boolean[][] visited) {
// 矩阵访问越界,当前位置已经被访问过,
// 当前位置不是陆地,直接停止搜索
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length ||
visited[i][j] || grid[i][j] != '1') {
return;
}
visited[i][j] = true;
DFS(grid, i - 1, j, visited);
DFS(grid, i + 1, j, visited);
DFS(grid, i, j - 1, visited);
DFS(grid, i, j + 1, visited);
}
public int numIslands(char[][] grid) {
// 特殊情况,如果矩阵为为空,直接返回0
if (grid.length==0||grid[0].length==0){
return 0;
}
int row = grid.length, col = grid[0].length;
int count = 0;
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if (grid[i][j] == '1' ) {
count++;
DFS(grid, i, j);
}
}
}
return count;
}
public void DFS(char[][] grid, int i, int j) {
// 矩阵访问越界,当前位置已经被访问过,
// 当前位置不是陆地,直接停止搜索
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length ||
grid[i][j] != '1') {
return;
}
grid[i][j] = '0';
DFS(grid, i - 1, j);
DFS(grid, i + 1, j);
DFS(grid, i, j - 1);
DFS(grid, i, j + 1);
}
private int[][] direct = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public int numDistinctIslands(int[][] grid) {
// 特殊情况
if (grid.length == 0 || grid[0].length == 0) {
return 0;
}
// 使用set存放每个岛屿的形状,形状用0,1,2,3表示上下左右
HashSet<List<String>> ilandShape = new HashSet<>();
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == 1) {
List<String> item = new ArrayList<>();
dfsDistinct(grid, i, j, item);
ilandShape.add(item);
}
}
}
return ilandShape.size();
}
public void dfsDistinct(int[][] grid, int i, int j, List<String> list) {
if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] != 1) {
return;
}
grid[i][j] = 0;
for (int d = 0; d < 4; d++) {
list.add(String.valueOf(d));
dfsDistinct(grid, i + direct[d][0], j + direct[d][1], list);
}
}