剑指 Offer 03. 数组中重复的数字
哈希表
/*
//java 2020.7.25
在哈希表中添加数据,如果表中已经有该项,直接返回即可
*/
class Solution {
public int findRepeatNumber(int[] nums) {
Map<Integer, Integer> map = new HashMap<>(); //数据采用的哈希表结构
int res = 0;
//在哈希表中添加数据
// for(int i = 0; i < nums.length; i++){
// if(map.containsKey(nums[i])){
// res = nums[i];
// }else{
// map.put(nums[i], 1);
// }
// }
//可以直接使用for each循环
for(int num: nums){
if(map.containsKey(num)){
res = num;
}else{
map.put(num, 1);
}
}
return res;
}
}
(官方)集合
class Solution {
public int findRepeatNumber(int[] nums) {
Set<Integer> set = new HashSet<Integer>();
int repeat = -1;
for (int num : nums) {
if (!set.add(num)) {
repeat = num;
break;
}
}
return repeat;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/solution/mian-shi-ti-03-shu-zu-zhong-zhong-fu-de-shu-zi-b-4/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer 04. 二维数组中的查找
//java 安安 2020.7.25 还可按照题解改进
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
boolean flag = false;
for(int i = matrix.length-1; i >= 0 ; i--){
for(int j = 0; j < matrix[0].length; j++){
if(matrix[i][j] > target){
break;
}else if(matrix[i][j] == target){
flag = true;
}
//System.out.print(matrix[i][j] + " ");
}
//System.out.println();
}
return flag;
}
}
//java 2020.7.25 官解
class Solution {
public boolean findNumberIn2DArray(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { //先判断特殊情况
return false;
}
int rows = matrix.length, columns = matrix[0].length;
int row = 0, column = columns - 1;
while (row < rows && column >= 0) {
int num = matrix[row][column];
if (num == target) {
return true;
} else if (num > target) {
column--;
} else {
row++;
}
}
return false;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof/solution/mian-shi-ti-04-er-wei-shu-zu-zhong-de-cha-zhao-b-3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer 05. 替换空格
1.字符串替换函数
//anan 直接用字符串替换函数
class Solution {
public String replaceSpace(String s) {
String res = s.replace(" ", "%20");
return res;
}
}
2.StringBuilder
//anan 用StringBulider
class Solution {
public String replaceSpace(String s) {
StringBuilder sb = new StringBuilder();
for(int i = 0; i < s.length(); i++){
//if(s.charAt(i) == " "){ //不能用双引号
if(s.charAt(i) == ' '){
sb.append("%20");
}else{
sb.append(s.charAt(i));
}
}
return sb.toString();
}
}
2代码改进
class Solution {
public String replaceSpace(String s) {
StringBuilder res = new StringBuilder();
for(Character c : s.toCharArray())
{
if(c == ' ') res.append("%20");
else res.append(c);
}
return res.toString();
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/solution/mian-shi-ti-05-ti-huan-kong-ge-ji-jian-qing-xi-tu-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
(官方)字符数组
class Solution {
public String replaceSpace(String s) {
int length = s.length();
char[] array = new char[length * 3];
int size = 0;
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
if (c == ' ') {
array[size++] = '%';
array[size++] = '2';
array[size++] = '0';
} else {
array[size++] = c;
}
}
String newStr = new String(array, 0, size);
return newStr;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof/solution/mian-shi-ti-05-ti-huan-kong-ge-by-leetcode-solutio/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer 06. 从尾到头打印链表
两次遍历,第一次数长度,第二次填充数值
//先判断链表个数,按照这个长度申请数组,从头到尾第二次遍历链表的时候从后往前填充数组
class Solution {
public int[] reversePrint(ListNode head) {
ListNode p = head;
int length = 0;
while(p != null){
length++;
p = p.next;
}
//System.out.println(length);
int[] res = new int[length];
p = head;
for(int i = 0; p != null; p = p.next, i++){
//System.out.println(p.val);
res[length-1-i] = p.val;
}
return res;
}
}
(官方)辅助栈
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public int[] reversePrint(ListNode head) {
Stack<ListNode> stack = new Stack<ListNode>();
ListNode temp = head;
while (temp != null) {
stack.push(temp);
temp = temp.next;
}
int size = stack.size();
int[] print = new int[size];
for (int i = 0; i < size; i++) {
print[i] = stack.pop().val;
}
return print;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/solution/mian-shi-ti-06-cong-wei-dao-tou-da-yin-lian-biao-b/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
(别人)递归法
利用递归: 先走至链表末端,回溯时依次将节点值加入列表 ,这样就可以实现链表值的倒序输出
class Solution {
ArrayList<Integer> tmp = new ArrayList<Integer>();
public int[] reversePrint(ListNode head) {
recur(head);
int[] res = new int[tmp.size()];
for(int i = 0; i < res.length; i++)
res[i] = tmp.get(i);
return res;
}
void recur(ListNode head) {
if(head == null) return;
recur(head.next);
tmp.add(head.val);
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/solution/mian-shi-ti-06-cong-wei-dao-tou-da-yin-lian-biao-d/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer 07. 重建二叉树
复制数组 太费空间了
//anan java 2020.7.28
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return recur(preorder, inorder);
}
public TreeNode recur(int[] preorder, int[] inorder){
//System.out.println("preorder:" + Arrays.toString(preorder));
//System.out.println("inorder:" + Arrays.toString(inorder));
if(preorder.length == 0) return null;
TreeNode root = new TreeNode();
root.val = preorder[0];
int rootIndex = -1;
for(int i = 0; i < inorder.length; i++){
if(inorder[i] == preorder[0]){
rootIndex = i;
break;
}
}
//System.out.println("left");
root.left = recur(Arrays.copyOfRange(preorder,1, rootIndex+1), java.util.Arrays.copyOfRange(inorder,0, rootIndex));
//System.out.println("right");
root.right = recur(Arrays.copyOfRange(preorder, rootIndex+1, preorder.length), java.util.Arrays.copyOfRange(inorder,rootIndex+1, inorder.length));
return root;
}
}
直接在原数组操作,灵活应用下标
//anan
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return recur(preorder, 0, preorder.length-1, inorder, 0, inorder.length-1);
}
public TreeNode recur(int[] preorder, int pre, int preEnd, int[] inorder, int in, int inEnd){
//System.out.println("preorder:" + Arrays.toString(preorder));
//System.out.println("inorder:" + Arrays.toString(inorder));
if(pre > preEnd) return null;
TreeNode root = new TreeNode();
root.val = preorder[pre];
if(pre == preEnd ) return root;
int rootIndex = -1;
int length = 0;
for(int i = in; i < inEnd+1; i++){
if(inorder[i] == preorder[pre]){
rootIndex = i;
break;
}
}
length = rootIndex-in;
System.out.println("left");
root.left = recur(preorder, pre+1, pre+length, inorder, in, rootIndex-1);
System.out.println("right");
root.right = recur(preorder, pre+length+1, preEnd, inorder, rootIndex+1, inEnd);
//root.right = recur(preorder, pre+length+1, preorder.length-1, inorder, rootIndex+1, inorder.length-1); //错误 原因:右子树的终点不一定都在数组末尾
return root;
}
}
(官方)hashmap提高了效率
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder == null || preorder.length == 0) {
return null;
}
Map<Integer, Integer> indexMap = new HashMap<Integer, Integer>();
int length = preorder.length;
for (int i = 0; i < length; i++) {
indexMap.put(inorder[i], i);
}
TreeNode root = buildTree(preorder, 0, length - 1, inorder, 0, length - 1, indexMap);
return root;
}
public TreeNode buildTree(int[] preorder, int preorderStart, int preorderEnd, int[] inorder, int inorderStart, int inorderEnd, Map<Integer, Integer> indexMap) {
if (preorderStart > preorderEnd) {
return null;
}
int rootVal = preorder[preorderStart];
TreeNode root = new TreeNode(rootVal);
if (preorderStart == preorderEnd) {
return root;
} else {
int rootIndex = indexMap.get(rootVal);
int leftNodes = rootIndex - inorderStart, rightNodes = inorderEnd - rootIndex;
TreeNode leftSubtree = buildTree(preorder, preorderStart + 1, preorderStart + leftNodes, inorder, inorderStart, rootIndex - 1, indexMap);
TreeNode rightSubtree = buildTree(preorder, preorderEnd - rightNodes + 1, preorderEnd, inorder, rootIndex + 1, inorderEnd, indexMap);
root.left = leftSubtree;
root.right = rightSubtree;
return root;
}
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/mian-shi-ti-07-zhong-jian-er-cha-shu-by-leetcode-s/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer 09. 用两个栈实现队列
自己写的用的stack
//java anan 2020.7.29
class CQueue {
Stack<Integer> stack1 = new Stack<>(); //存放数据
Stack<Integer> stack2 = new Stack<>(); //输出时的辅助栈
public CQueue() {
}
public void appendTail(int value) {
stack1.push(value);
}
//这种删除方式有点繁琐
public int deleteHead() {
if(stack1.empty()){ //stack1为空,说明队列为空
return -1;
}
while(!stack1.empty()){
stack2.push(stack1.pop());
}
int res = stack2.pop();
while(!stack2.empty()){
stack1.push(stack2.pop());
}
return res;
}
}
/**
* Your CQueue object will be instantiated and called as such:
* CQueue obj = new CQueue();
* obj.appendTail(value);
* int param_2 = obj.deleteHead();
*/
(结合官解和别人的)用的deque和linkedlist
//stack1 支持插入操作,stack2 支持删除操作
class CQueue {
Deque<Integer> stack1;
Deque<Integer> stack2;
public CQueue() {
stack1 = new LinkedList<>();
stack2 = new LinkedList<>();
}
public void appendTail(int value) {
stack1.push(value);
}
public int deleteHead() {
if(!stack2.isEmpty()){
return stack2.pop();
}
if(stack1.isEmpty()){
return -1;
}
while(!stack1.isEmpty()){
stack2.push(stack1.pop());
}
return stack2.pop();
}
}
剑指 Offer 10- I. 斐波那契数列(dp模板)
安安:动态规划 double 数据类型不兼容,故用了强制类型转化
//java anan 2020.7.29
class Solution {
public int fib(int n) {
if(n == 0) return 0;
double[] res = new double[n+1];
res[0] = 0;
res[1] = 1;
for(int i = 2; i < n+1; i++){
res[i] = (res[i-1] + res[i-2]) % (1e9+7);
}
//System.out.println(Arrays.toString(res));
return (int)res[n];
}
}
安安改进:类型改进dp
//java anan改进 把1e9+7改成了1000000007
class Solution {
public int fib(int n) {
if(n == 0) return 0;
int[] res = new int[n+1];
res[0] = 0;
res[1] = 1;
for(int i = 2; i < n+1; i++){
//res[i] = (res[i-1] + res[i-2]) % (1e9+7);
//Line 10: error: incompatible types: possible lossy conversion from double to int
//1e9+7是浮点数的表示方式,所以会出现这个错误,改成整数形式的就好了
res[i] = (res[i-1] + res[i-2]) % (1000000007);
}
//System.out.println(Arrays.toString(res));
return res[n];
}
}
官解和别人:空间优化
class Solution {
public int fib(int n) {
if(n <= 1) return n;
int a = 0, b = 1, sum=0;
for(int i = 2; i < n+1; i++){
sum = (a+b)%1000000007;
a = b;
b = sum;
}
return sum;
}
}
递归:会超时
class Solution {
public int fib(int n) {
if(n == 0 || n == 1) return n;
return fib(n-1) + fib(n-2);
}
}
记忆化递归
class Solution {
private int[] memo;
public int fib(int n) {
memo = new int[n+1]; //创建记忆数组
Arrays.fill(memo, -1);
if (n <= 1) return n;
memo[0] = 0;
memo[1] = 1;
return memoize(n);
}
public int memoize(int n) {
if (memo[n] != -1) { //如果数组里有值,说明之前算过,直接返回即可
return memo[n];
}
memo[n] = (memoize(n-1) + memoize(n-2))%(1000000007);
return memo[n];
}
}
剑指 Offer 10- II. 青蛙跳台阶问题
//java anan 2020.7.29
class Solution {
public int numWays(int n) {
if(n == 0 || n == 1) return 1;
int[] dp = new int[n+1];
dp[1] = 1;
dp[2] = 2;
for(int i = 3; i < n+1; i++){
dp[i] = (dp[i-1]+dp[i-2]) % (1000000007);
}
return dp[n];
}
}
153. 寻找旋转排序数组中的最小值
二分法
我们希望找到旋转排序数组的最小值,如果数组没有被旋转呢?如何检验这一点呢?
如果数组没有被旋转,是升序排列,就满足 last element > first element。
//二分法查找
class Solution {
public int findMin(int[] nums) {
int left = 0, right = nums.length - 1;
while (left < right) {
int middle = left + (right-left) / 2;
//int middle = (left + right) / 2; 这样写可能会溢出
if (nums[middle] < nums[right]) { //[5 6 7 1 2 3 4]
// middle可能是最小值
right = middle;
} else { //[5 6 7 1 2 3]
// middle肯定不是最小值
left = middle + 1;
}
}
return nums[left];
}
}
剑指 Offer 11. 旋转数组的最小数字
//二分法查找
class Solution {
public int findMin(int[] nums) {
int left = 0, right = nums.length - 1;
while (left < right) {
int middle = left + (right-left) / 2;
//int middle = (left + right) / 2; 这样写可能会溢出
if (nums[middle] < nums[right]) {
// middle可能是最小值
right = middle;
} else if(nums[middle] > nums[right]){
// middle肯定不是最小值
left = middle + 1;
} else{
right--;
}
}
return nums[left];
//return Math.min(nums[left],nums[right]);//最后答案定位在了两个数字,小的那个即为答案
//这个是看到别人的题解里的,如果最后很难判别,就这样写,也算是一个小技巧吧
}
}
33. 搜索旋转排序数组
class Solution {
public int search(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return -1;
}
int start = 0;
int end = nums.length - 1;
int mid;
while (start <= end) {
mid = start + (end - start) / 2;
if (nums[mid] == target) {
return mid;
}
//前半部分有序,注意此处用小于等于
if (nums[start] <= nums[mid]) {
//target在前半部分
if (target >= nums[start] && target < nums[mid]) {
end = mid - 1;
} else {
start = mid + 1;
}
} else {
if (target <= nums[end] && target > nums[mid]) {
start = mid + 1;
} else {
end = mid - 1;
}
}
}
return -1;
}
// 作者:reedfan
// 链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/ji-bai-liao-9983de-javayong-hu-by-reedfan/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
}
81. 搜索旋转排序数组 II
public boolean search(int[] nums, int target) {
if (nums == null || nums.length == 0) {
return false;
}
int start = 0;
int end = nums.length - 1;
int mid;
while (start <= end) {
mid = start + (end - start) / 2;
if (nums[mid] == target) {
return true;
}
if (nums[start] == nums[mid]) {
start++;
continue;
}
//前半部分有序
if (nums[start] < nums[mid]) {
//target在前半部分
if (nums[mid] > target && nums[start] <= target) {
end = mid - 1;
} else { //否则,去后半部分找
start = mid + 1;
}
} else {
//后半部分有序
//target在后半部分
if (nums[mid] < target && nums[end] >= target) {
start = mid + 1;
} else { //否则,去后半部分找
end = mid - 1;
}
}
}
//一直没找到,返回false
return false;
}
作者:reedfan
链接:https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii/solution/zai-javazhong-ji-bai-liao-100de-yong-hu-by-reedfan/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
剑指 Offer 12. 矩阵中的路径
anan dfs
//anan
/*
遍历矩阵,找到和字符串第一个字母相同的位置
从该位置开始,上下左右开始找和字符串第二个字母相同的位置
*/
class Solution {
public boolean exist(char[][] board, String word) {
int i0;
int j0;
int index = 0;
boolean[][] flag = new boolean[board.length][board[0].length];
for(int i = 0; i < board.length; i++){
for(int j = 0; j < board[0].length; j++){
//System.out.print(board[i][j] + " ");
if(board[i][j] == word.charAt(0)){
i0 = i;
j0 = j;
//System.out.println("主函数:" + i0 + " " + j0);
if(recur(board, i0, j0, word, 0, flag) == true){
return true;
}
}
}
//System.out.println();
}
return false;
}
public boolean recur(char[][] board, int i, int j, String word, int index, boolean[][] flag){
boolean res;
if(index >= word.length()){
return true;
}
if(i >= 0 && i < board.length && j >= 0 && j < board[0].length && flag[i][j] == false && board[i][j] == word.charAt(index)){
//System.out.println("位置:" + i + " " + j + " " + board[i][j]);
flag[i][j] = true;
//showFlag(flag);
res = recur(board, i-1, j, word, index+1, flag) || recur(board, i, j-1, word, index+1, flag) || recur(board, i+1, j, word, index+1, flag) || recur(board, i, j+1, word, index+1, flag); //上左下右
flag[i][j] = false; //递归完一定要把flag变回去,因为每次递归用的都是同一个flag
return res;
}else{
return false;
}
}
public void showFlag(boolean[][] flag){
for(int i = 0; i < flag.length; i++){
for(int j = 0; j < flag[0].length; j++){
System.out.print((flag[i][j] == true ? 1 :0) + " ");
}
System.out.println();
}
}
}
dfs代码改进 加了全局变量
/*
本问题是典型的矩阵搜索问题,可使用 深度优先搜索(DFS)+ 剪枝 解决。
*/
class Solution {
private char[][] board;
private String word;
private int rows;
private int cols;
private boolean[][] marked;
public boolean exist(char[][] board, String word) {
this.board = board; //两个变量名字一样,所以要加this
this.word = word;
rows = board.length; //只有一个,不用加this
cols = board[0].length;
marked = new boolean[rows][cols];
if(rows == 0) return false;
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
if(dfs(i, j, 0) == true){ //第一个位置也可以在递归里进行判定
return true;
}
}
}
return false;
}
public boolean dfs(int i, int j, int index){ //index表示String的下标
if(index >= word.length()) return true;
if(i < 0 || i >= rows || j < 0 || j >= cols || marked[i][j] == true || board[i][j] != word.charAt(index)) return false;
marked[i][j] = true;
boolean res = dfs(i-1, j, index+1) || dfs(i, j-1, index+1) || dfs(i+1, j, index+1) || dfs(i, j+1, index+1); //上左下右
marked[i][j] = false; //递归完一定要把flag变回去,因为每次递归用的都是同一个flag
return res;
}
}
dfs 没有用标记数组
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;
char tmp = board[i][j];
board[i][j] = '/';
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] = tmp;
return res;
}
}
// 作者:jyd
// 链接:https://leetcode-cn.com/problems/ju-zhen-zhong-de-lu-jing-lcof/solution/mian-shi-ti-12-ju-zhen-zhong-de-lu-jing-shen-du-yo/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
dfs 用了偏移量数组
class Solution {
private char[][] board;
private String word;
private int rows;
private int cols;
private boolean[][] marked;
private int[][] direction = {{-1, 0}, {0, -1}, {0, 1}, {1, 0}}; //上左下右
// x-1,y
// x,y-1 x,y x,y+1
// x+1,y
public boolean exist(char[][] board, String word) {
this.board = board; //两个变量名字一样,所以要加this
this.word = word;
rows = board.length; //只有一个,不用加this
cols = board[0].length;
marked = new boolean[rows][cols];
if(rows == 0) return false;
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
if(dfs(i, j, 0) == true){ //第一个位置也可以在递归里进行判定
return true;
}
}
}
return false;
}
public boolean dfs(int i, int j, int index){ //index表示String的下标
if(index >= word.length()) return true;
if(i < 0 || i >= rows || j < 0 || j >= cols || marked[i][j] == true || board[i][j] != word.charAt(index)) return false;
marked[i][j] = true;
for(int k = 0; k < 4; k++){
if(dfs(i + direction[k][0], j + direction[k][1], index+1) == true){
return true;
}
}
//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);
//之前是用或的方式递归的,现在用偏移量数组
marked[i][j] = false; //递归完一定要把flag变回去,因为每次递归用的都是同一个flag
return false;
}
}
200. 岛屿数量
anan dfs
/*
安安理解:如何判定这是一个岛屿?
这片区域都是1,这片区域的外围都是0
1的话就一直递归,0的话就停止
*/
class Solution {
private char[][] grid;
private int rows;
private int cols;
private boolean[][] marked;
private int count;
private boolean flag;
public int numIslands(char[][] grid) {
this.grid = grid;
rows = grid.length;
if(rows == 0) return 0; //这个判断必须要在此处,如果放到后面就会出错
cols = grid[0].length;
marked = new boolean[rows][cols];
count = 0; //统计岛屿的个数
flag = false;
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
dfs(i, j);
if(flag == true){
count++;
//System.out.println("count:" + count);
flag = false;
}
}
}
return count;
}
public boolean dfs(int i, int j){
if(i<0 || i>=rows || j<0 || j>=cols || marked[i][j]==true || grid[i][j]=='0') return false;
//System.out.println(i + " " + j + " " + grid[i][j]);
marked[i][j] = true; //标记过后,不再擦掉。因此标记了就说明该位置已经和其他地方连成一片了
boolean res = dfs(i-1,j) || dfs(i,j-1) || dfs(i+1,j) || dfs(i,j+1);
//当最后4个人方向全部为false的时候,说明已经形成一个岛屿了
//为什么不直接在这count++?因为这样回溯的时候会使count累加次数过多
if(res == false){
flag = true;
}
return res;
}
}
dfs 改进
/*
我们可以将二维网格看成一个无向图,竖直或水平相邻的 11 之间有边相连。
为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为 11,则以其为起始节点开始进行深度优先搜索。在深度优先搜索的过程中,每个搜索到的 11 都会被重新标记为 00。
最终岛屿的数量就是我们进行深度优先搜索的次数。
作者:LeetCode
链接:https://leetcode-cn.com/problems/number-of-islands/solution/dao-yu-shu-liang-by-leetcode/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
class Solution {
private char[][] grid;
private int rows;
private int cols;
public int numIslands(char[][] grid) {
this.grid = grid;
rows = grid.length;
if(rows == 0 || grid == null) return 0;
cols = grid[0].length;
int count; = 0; //统计岛屿的个数
for(int i = 0; i < rows; i++){
for(int j = 0; j < cols; j++){
if(grid[i][j] == '1'){
dfs(i, j);
count++;
}
}
}
return count;
}
public void dfs(int i, int j){ //我们看到,最后判断岛屿数量并不需要dfs的回溯结果,所以设置为void
if(i<0 || i>=rows || j<0 || j>=cols || grid[i][j]=='0') return;
grid[i][j] = '0'; //此处不必再加marked数组
dfs(i-1,j);
dfs(i,j-1);
dfs(i+1,j);
dfs(i,j+1);
}
}
DFS
class Solution {
public int numIslands(char[][] grid) {
int count = 0;
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[0].length; j++) {
if(grid[i][j] == '1'){
dfs(grid, i, j);
count++;
}
}
}
return count;
}
private void dfs(char[][] grid, int i, int j){
if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') return;
grid[i][j] = '0'; //这个地方最好不要用0
//在一些题解中,可能会把「已遍历过的陆地格子」标记为和海洋格子一样的 0,美其名曰「陆地沉没方法」,即遍历完一个陆地格子就让陆地「沉没」为海洋。这种方法看似很巧妙,但实际上有很大隐患,因为这样我们就无法区分「海洋格子」和「已遍历过的陆地格子」了。如果题目更复杂一点,这很容易出 bug。
dfs(grid, i + 1, j);
dfs(grid, i, j + 1);
dfs(grid, i - 1, j);
dfs(grid, i, j - 1);
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/number-of-islands/solution/number-of-islands-shen-du-you-xian-bian-li-dfs-or-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
BFS
lass Solution {
public int numIslands(char[][] grid) {
int count = 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);
count++;
}
}
}
return count;
}
private void bfs(char[][] grid, int i, int j){
Queue<int[]> list = new LinkedList<>();
list.add(new int[] { i, j });
while(!list.isEmpty()){
int[] cur = list.remove();
i = cur[0]; j = cur[1];
if(0 <= i && i < grid.length && 0 <= j && j < grid[0].length && grid[i][j] == '1') {
grid[i][j] = '0';
list.add(new int[] { i + 1, j });
list.add(new int[] { i - 1, j });
list.add(new int[] { i, j + 1 });
list.add(new int[] { i, j - 1 });
}
}
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/number-of-islands/solution/number-of-islands-shen-du-you-xian-bian-li-dfs-or-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
695. 岛屿的最大面积
class Solution {
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){ //开始遍历
res = Math.max(res, dfs(grid, i, j));
}
}
}
return res;
}
public int dfs(int[][] grid, int i, int j){
if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] != 1) return 0;
grid[i][j] = 2;
return 1 + dfs(grid, i-1, j) + dfs(grid, i+1, j) + dfs(grid, i, j-1) + dfs(grid, i, j+1);
}
}
463. 岛屿的周长
//题目说明 只有一个岛屿
class Solution {
public int islandPerimeter(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){ //开始遍历
res = dfs(grid, i, j);
}
}
}
return res;
}
public int dfs(int[][] grid, int i, int j){
if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) return 1;
if(grid[i][j] == 2) return 0;
grid[i][j] = 2;
return dfs(grid, i-1, j) + dfs(grid, i+1, j) + dfs(grid, i, j-1) + dfs(grid, i, j+1);
}
}
剑指 Offer 13. 机器人的运动范围
anan dfs
class Solution {
boolean[][] marked;
public int movingCount(int m, int n, int k) {
if(m == 0 || n == 0) return 0;
marked = new boolean[m][n];
return dfs(m,n,0,0,k);
}
public int dfs(int m, int n, int i, int j, int k){
if(i < 0 || i >= m || j < 0 || j >= n || (sum(i)+sum(j)) > k || marked[i][j] == true) return 0;
marked[i][j] = true;
return 1 + dfs(m,n,i-1,j,k) + dfs(m,n,i,j-1,k) + dfs(m,n,i+1,j,k) + dfs(m,n,i,j+1,k);
}
public int sum(int x){
int sum = 0;
while(x != 0){
sum += x%10;
x /= 10;
}
return sum;
}
}
dfs改进:考虑两个方向就可以了 向下和向右
class Solution {
boolean[][] marked; //marked可以换为visited,更形象
public int movingCount(int m, int n, int k) {
if(m == 0 || n == 0) return 0;
marked = new boolean[m][n];
return dfs(m,n,0,0,k);
}
public int dfs(int m, int n, int i, int j, int k){
if(i < 0 || i >= m || j < 0 || j >= n || (sum(i)+sum(j)) > k || marked[i][j] == true) return 0;
marked[i][j] = true;
return 1 + dfs(m,n,i+1,j,k) + dfs(m,n,i,j+1,k);
}
public int sum(int x){
int sum = 0;
while(x != 0){
sum += x%10;
x /= 10;
}
return sum;
}
}
bfs
class Solution {
private boolean[][] marked;
private int res;
public int movingCount(int m, int n, int k) {
if(m == 0 || n == 0) return 0;
marked = new boolean[m][n];
res = 0;
bfs(m,n,0,0,k);
return res;
}
public void bfs(int m, int n, int i, int j, int k){
Queue<int[]> list = new LinkedList<>();
list.add(new int[] {0, 0});
while(!list.isEmpty()){
int[] cur = list.remove();
i = cur[0];
j = cur[1];
if(i < 0 || i >= m || j < 0 || j >= n || (sum(i)+sum(j)) > k || marked[i][j] == true) continue;
marked[i][j] = true;
res++;
list.add(new int[] {i+1, j});
list.add(new int[] {i, j+1});
}
}
public int sum(int x){
int sum = 0;
while(x != 0){
sum += x%10;
x /= 10;
}
return sum;
}
}
剑指 Offer 14- I. 剪绳子
anan 递归 超时 超过了41就通过不了了
class Solution {
private int max;
public int cuttingRope(int n) {
max = 0;
if(n < 2) return n;
for(int i = 2; i <= n; i++){ //长度为n的绳子,可以剪为2、3、...、n段
dfs(n, i, 1);
}
return max;
}
//功能:把长度为n的绳子剪为m段
public void dfs(int n, int m, int mul){
//System.out.println("mul:" + mul + " max:" + max);
if(m == 1){
max = Math.max(max, mul*n);
return;
}
for(int i = 1; i <= n/m; i++){
dfs(n-i, m-1, mul*i);
max = Math.max(max, mul*i);
}
}
}
动态规划
class Solution {
public int cuttingRope(int n) {
int[] dp = new int[n+1];
if(n < 2) return n;
dp[1] = 1;
for(int i = 2; i <= n; i++){
int curMax = 0;
for(int j = 1; j < i; j++){
curMax = Math.max(curMax, Math.max(j*dp[i-j], j*(i-j))); //因为拆的时候不能拆成1段,但是后面算的时候是可以把前面的看成一个整体的
}
dp[i] = curMax;
}
return dp[n];
}
}
剑指 Offer 14- II. 剪绳子 II
贪心思想 + 快速幂求余
class Solution {
public int cuttingRope(int n) {
if(n <= 3) return n - 1;
int b = n % 3, p = 1000000007;
long rem = 1, x = 3;
for(int a = n / 3 - 1; a > 0; a /= 2) {
if(a % 2 == 1) rem = (rem * x) % p;
x = (x * x) % p;
}
if(b == 0) return (int)(rem * 3 % p);
if(b == 1) return (int)(rem * 4 % p);
return (int)(rem * 6 % p);
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof/solution/mian-shi-ti-14-ii-jian-sheng-zi-iitan-xin-er-fen-f/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
BigInteger
import java.math.BigInteger;
class Solution {
public int cuttingRope(int n) {
if(n<2)
return 0;
if(n==2)
return 1;
if(n==3)
return 2;
/*
d[i]表示长度为i的绳子剪完后各段乘积的最大值, 最终目标是dp[n]
dp[i]可以看成是长度为i-k的绳子的最大值和长度为k的绳子的最大值的乘积, 子问题最优, 所以dp[i]也是最优
状态转移方程: dp[i] = max(dp[i], dp[i-k]*dp[k])
*/
//下面的初始值不同于上面的特殊情况, 上面是必须剪一刀, 下面的三个初始值不用再减了
BigInteger[] dp = new BigInteger[n+1];
dp[1] = new BigInteger("1");//内循环中会用到这个值
dp[2] = new BigInteger("2");
dp[3] = new BigInteger("3");
for(int i=4; i<=n; i++){
//初始化dp[i]
dp[i] = new BigInteger("0");
//长度为i的绳子有i-1个剪切位置; 不论i是奇数还是偶数, 只考虑前i/2个剪切位置即可, 后面的剪切位置是重复的
for(int j=1; j<=i/2; j++){
//因为j和i-j都小于i, 所以这是自底向上的计算方式
dp[i] = dp[i].max(dp[j].multiply(dp[i-j]));
}
}
return dp[n].mod(new BigInteger("1000000007")).intValue();
}
}
作者:littlehaes
链接:https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof/solution/java-dong-tai-gui-hua-ji-bai-100-he-jian-sheng-zi-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。