1、岛屿的最大面积
给你一个大小为 m x n 的二进制矩阵 grid 。
岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
岛屿的面积是岛上值为 1 的单元格的数目。
计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。
时间复杂度:$O(m*n)
空间复杂度:$O(1)
class Solution {
int sum = 0;
public int maxAreaOfIsland(int[][] grid) {
int res = 0;
for(int i = 0; i < grid.length; i++){
for(int j = 0; j < grid[0].length; j++){
if(grid[i][j] == 1){
bfs(grid,i,j);
res = Math.max(sum,res);
sum = 0;
}
}
}
return res;
}
public void bfs(int[][] 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] = 2;
sum++;
bfs(grid,i - 1,j);
bfs(grid,i + 1,j);
bfs(grid,i,j - 1);
bfs(grid,i, j + 1);
}
}
2、最后一块石头的重量 II
有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。
每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x 和 y,且 x <= y。那么粉碎的可能结果如下:
如果 x == y,那么两块石头都会被完全粉碎;
如果 x != y,那么重量为 x 的石头将会完全粉碎,而重量为 y 的石头
新重量为 y-x。最后,最多只会剩下一块 石头。返回此石头 最小的可能重量 。如果没有石头剩下,就返回 0。
class Solution {
public int lastStoneWeightII(int[] stones) {
if(stones == null || stones.length == 0){
return 0;
}
int sum = 0;
for(int stone : stones){
sum += stone;
}
int target = sum / 2;
int[] dp = new int[target + 1];
for(int i = 0; i < stones.length; i++){
for(int j = target; j>=stones[i];j--){
dp[j] = Math.max(dp[j],dp[j - stones[i]] + stones[i]);
}
}
return sum - 2 * dp[target];
}
}
3、分割等和子集
给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
class Solution {
public boolean canPartition(int[] nums) {
if(nums == null || nums.length == 0){
return false;
}
int n = nums.length;
int sum = 0;
for(int num : nums){
sum += num;
}
if(sum % 2 != 0){
return false;
}
int target = sum / 2;
int[] dp = new int[target + 1];
for(int i = 0; i < n; i++){
for(int j = target;j >= nums[i];j--){
dp[j] = Math.max(dp[j],dp[j - nums[i]] + nums[i]);
}
}
return dp[target] == target;
}
}
4、不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
for(int i = 0; i < m; i++){
dp[i][0] = 1;
}
for(int i = 0; i < n; i++){
dp[0][i] = 1;
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
}
5、不同路径 II
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] dp = new int[m][n];
for(int i = 0; i < m; i++){
if(obstacleGrid[i][0] == 1){
break;
}
dp[i][0] = 1;
}
for(int i = 0; i < n; i++){
if(obstacleGrid[0][i] == 1){
break;
}
dp[0][i] = 1;
}
for(int i = 1; i < m; i++){
for(int j = 1; j < n; j++){
if(obstacleGrid[i][j] == 1){
continue;
}
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
}
6、矩阵中的路径
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
class Solution {
public boolean exist(char[][] board, String word) {
char[] words = word.toCharArray();
for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
if(dfs(board, words, i, j, 0)) return true;
}
}
return false;
}
boolean dfs(char[][] board, char[] word, int i, int j, int k) {
if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;
if(k == word.length - 1) return true;
board[i][j] = '\0';
boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) ||
dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
board[i][j] = word[k];
return res;
}
}
7、机器人的运动范围
地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?
class Solution {
int m,n,k;
boolean visited[][];
public int movingCount(int m, int n, int k) {
this.m = m;
this.n = n;
this.k = k;
this.visited = new boolean[m][n];
return dfs(0,0);
}
// 计算位数和函数
int sum(int n){
int res = 0;
while(n!=0){
res+=n%10;
n = n/10;
}
return res;
}
int dfs(int x,int y){
if(sum(x) + sum(y) > k || x>=m || y>=n || visited[x][y]){
return 0;
}else{
visited[x][y]=true; //标记为走过
return 1+ dfs(x+1,y)+dfs(x,y+1); //返回当前计数1以及继续往下和右两个方向dfs
}
}
}
8、迷路的机器人
设想有个机器人坐在一个网格的左上角,网格 r 行 c 列。机器人只能向下或向右移动,但不能走到一些被禁止的网格(有障碍物)。设计一种算法,寻找机器人从左上角移动到右下角的路径。
class Solution {
int m, n;
List<List<Integer>> ans = new ArrayList<>();
boolean flag = false; //标记是否找到目的地
public List<List<Integer>> pathWithObstacles(int[][] obstacleGrid) {
m = obstacleGrid.length; n = obstacleGrid[0].length;
dfs(0, 0, obstacleGrid);
return ans;
}
public void dfs(int x, int y, int[][] obstacleGrid) {
if (x < 0 || x >= m || y < 0 || y >= n || obstacleGrid[x][y] == 1) return; //不能到达的方格
ans.add(Arrays.asList(x, y));
obstacleGrid[x][y] = 1; //每个点最多处理一次,因此第一次处理过的点都作个标记
if (x == m - 1 && y == n - 1) flag = true; //成功找到目的地就作标记
if (flag == false) dfs(x + 1, y, obstacleGrid); //未到达目的地就试着往下走
if (flag == false) dfs(x, y + 1, obstacleGrid); //未找到目的地就试着往右走
if (flag == false) ans.remove(ans.size() - 1); //往右往下走都没到达目的地,说明该点无效,作移除
}
}
9、最小路径和
给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
class Solution {
public int minPathSum(int[][] grid) {
int[][] dp = new int[grid.length][grid[0].length];
for(int i = 0; i < grid.length; i++){
for(int j = 0; j < grid[0].length; j++){
if(i == 0 && j == 0){
dp[i][j] = grid[i][j];
}else if(i != 0 && j == 0){
dp[i][j] = dp[i - 1][j] + grid[i][j];
}else if(i == 0 && j != 0){
dp[i][j] = dp[i][j - 1] + grid[i][j];
}else if(i != 0 && j != 0){
dp[i][j] = Math.min(dp[i - 1][j],dp[i][j - 1]) + grid[i][j];
}
}
}
return dp[grid.length - 1][grid[0].length - 1];
}
}
10、分发饼干
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。
对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子
会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。
class Solution {
public int findContentChildren(int[] g, int[] s) {
Arrays.sort(g);
Arrays.sort(s);
int left = 0;
int res = 0;
for(int i = 0; i < s.length && left < g.length; i++){
if(s[i] >= g[left]){
left++;
res++;
}
}
return res;
}
}