DFS
1. 岛屿的最大面积
package dfs;
import java.util.Arrays;
public class Solution_island {
public static int maxAreaOfIsland(int[][] grid) {
if(null == grid || grid.length == 0 || (grid.length == 1 && grid[0].length == 0))
return 0;
int max = Integer.MIN_VALUE;
int row = grid.length;
int col = grid[0].length;
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
if(grid[i][j] == 1){
max = Math.max(max, process(grid, i, j));
}
}
}
return max;
}
public static int process(int[][] grid, int a, int b){
if(a < 0 || a >= grid.length || b < 0 || b >= grid[0].length || grid[a][b] == 0) return 0;
int count = 1;
grid[a][b] = 0;
count += process(grid, a, b + 1) + process(grid, a + 1, b) + process(grid, a, b - 1) + process(grid, a - 1, b);
return count;
}
public static void main(String[] args) {
int[][] grid = {{1,0,1},{1,1,0},{0,0,1}};
System.out.println(maxAreaOfIsland(grid));
}
}
2. ***朋友圈
https://leetcode-cn.com/problems/friend-circles/
dfs
public static int findCircleNum(int[][] M) {
if(M == null || M.length == 0 || (M.length == 1 && M[0].length == 0)){
return 0;
}
int row = M.length;
int[] flag = new int[row];
int count = 0;
for(int i = 0; i < row; i++){
if(flag[i] == 0){
flag[i] = 1;
dfs(M, flag, i);
count++;
}
}
return count;
}
public static void dfs(int[][] arr, int[] flag, int k){
for(int i = 0; i < arr.length; i++){
if(arr[k][i] == 1 && flag[i] == 0){
flag[i] = 1;
dfs(arr, flag, i);
}
}
}
bfs
public static int findCircleNum(int[][] M) {
if(M == null || M.length == 0 || (M.length == 1 && M[0].length == 0)){
return 0;
}
int row = M.length;
int[] flag = new int[row];
int count = 0;
Queue<Integer> queue = new LinkedList<>();
for(int i = 0; i < row; i++){
if(flag[i] == 0){
count++;
flag[i] = 1;
queue.add(i);
while(!queue.isEmpty()){
int c = queue.poll();
for(int j = 0; j < row; j++){
if(M[c][j] == 1 && flag[j] == 0){
flag[j] = 1;
queue.add(j);
}
}
}
}
}
return count;
}
并查集
static int find(int parent[], int i) {
if (parent[i] == -1)
return i;
return find(parent, parent[i]);
}
static void union(int parent[], int x, int y) {
int xset = find(parent, x);
int yset = find(parent, y);
if (xset != yset)
parent[xset] = yset;
}
public static int findCircleNum(int[][] M) {
int[] parent = new int[M.length];
Arrays.fill(parent, -1);
for (int i = 0; i < M.length; i++) {
for (int j = 0; j < M.length; j++) {
if (M[i][j] == 1 && i != j) {
union(parent, i, j);
}
}
}
int count = 0;
for (int i = 0; i < parent.length; i++) {
System.out.print(parent[i] + " ");
if (parent[i] == -1)
count++;
}
System.out.println(" ");
return count;
}
BFS
1.腐烂的橘子
public class Solution_994 {
public static int orangesRotting(int[][] grid) {
if(grid == null || grid.length == 0 || (grid.length == 1 && grid[0].length == 0 )){
return 0;
}
//上下左右
int[] x = {-1, 1, 0, 0};
int[] y = {0, 0, -1, 1};
int row = grid.length;
int col = grid[0].length;
//广度优先搜索,将感染的橘子加入对列
Queue<Integer> queue = new LinkedList<>();
//value值为每个橘子被感染时,所代表的时间
HashMap<Integer, Integer> map = new HashMap<>();
int ans = 0;
for(int i = 0; i < row; i++){
for(int j = 0; j < col; j++){
if(grid[i][j] == 2){
//矩阵中的每个元素,可以根据坐标换算出唯一索引
int code = i * col + j;
queue.add(code);
//矩阵中原始腐坏的橘子,腐坏时间为0
map.put(code, 0);
}
}
}
while(!queue.isEmpty()){
int code = queue.remove();
int r = code / col;
int c = code % col;
for(int i = 0; i < 4; i++){
int rr = r + x[i];
int cc = c + y[i];
if(rr >= 0 && rr < row && cc >= 0 && cc < col && grid[rr][cc] == 1){
grid[rr][cc] = 2;
int code_infect = rr * col + cc;
queue.add(code_infect);
map.put(code_infect, map.get(code) + 1);
ans = map.get(code) + 1;
}
}
}
for(int[] arr : grid){
for(int v : arr){
if(v == 1){
return -1;
}
}
}
return ans;
}
public static void main(String[] args) {
// int[][] grid = {{2,1,1}, {1,1,0}, {0,1,1}};
int[][] grid = {{1, 2}};
System.out.println(orangesRotting(grid));
}
}
二分搜索
1.搜索旋转排序数组
我的解题方法比较麻烦,创建了一个新的方法用于对下标的控制。实际上用两个变量l和r
,然后用一个while
循环就可以。
关键点:使用二分,将数组分成两部分。其中一部分有序,一部分无序。使用nums[0] < nums[mid]
判断有序的部分,因为左半部分无序,右半部分肯定有序。
public static int search(int[] nums, int target) {
if(nums == null || nums.length == 0){
return -1;
}
int l = 0, r = nums.length - 1;
int mid;
while(l <= r){
mid = (l + r) / 2;
if(nums[mid] == target){
return mid;
}
if(nums[0] < nums[mid]){//左半部分有序
if(nums[0] <= target && target < nums[mid]){
r = mid - 1;
}else {
l = mid + 1;
}
}else{//右半部分有序
if(nums[mid] < target && target < nums[r]){
l = mid + 1;
}else{
r = mid - 1;
}
}
}
return -1;
}
2. 在排序数组中查找元素的第一个和最后一个位置
要求:时间复杂度为O(logN)
抠边界
//返回数组中第一个大于等于target的值的下标
private static int binarySearch(int[] nums, int target){
int start = 0;
int end = nums.length;
while(start < end){
int mid = (start + end) / 2;
if(nums[mid] == target){
end = mid;
}else if(nums[mid] < target){
start = mid + 1;
}else{
//本来我写的是end = mid - 1,但是不对呀
//因为最后return start,所以尽量让start右移
end = mid;
}
}
return start;
}
public static int[] searchRange(int[] nums, int target){
int[] defaultArr = {-1, -1};
int left = binarySearch(nums, target);
if(left == nums.length || nums[left] != target){
return defaultArr;
}
defaultArr[0] = left;
//注意这里
defaultArr[1] = binarySearch(nums, target + 1) - 1;
return defaultArr;
}