牛客网-剑指Offer刷题记录

emmm

赶在初一这天晚上终于把剑指Offer刷了一遍了,记录一下Coding的代码,希望接下来找工作顺利,上天保佑我;
牛客网剑指Offer67题

剑指Offer题记

JZ1

//从左上角开始找
public class Solution {
    public int JumpFloorII(int target) {
        if(target == 1 || target == 0) return 1;
        int[] res = new int[target+1];
        res[0] = res[1] = 1;
        for(int i = 2; i <= target; i++)
        {
            res[i] = 2 * res[i-1];
        }
        return res[target];
    }
}

JZ2

public class Solution {
    public String replaceSpace(StringBuffer str) {
    	StringBuffer res = new StringBuffer();
        for(int i = 0; i < str.length(); i++)
        {
            if(str.charAt(i) == ' ')
            {
                res.append('%');
                res.append('2');
                res.append('0');
            }
            else
            {
                res.append(str.charAt(i));
            }
        }
        return res.toString();
    }
}

JZ3

/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
public class Solution {
    //必须定义在方法外部
    ArrayList<Integer> res = new ArrayList<Integer>();
    
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        //递归实现
        if(listNode != null)
        {
            printListFromTailToHead(listNode.next);
            res.add(listNode.val);
        }
        return res;
    }
}
//利用栈
/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
import java.util.Stack;
public class Solution {    
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ArrayList list = new ArrayList();
        Stack stack = new Stack();
        while(listNode != null)
        {
            stack.push(listNode.val);
            listNode = listNode.next;
        }
        while(!stack.isEmpty())
        {
            list.add(stack.pop());
        }
        return list;
    }
}
/**
*    public class ListNode {
*        int val;
*        ListNode next = null;
*
*        ListNode(int val) {
*            this.val = val;
*        }
*    }
*
*/
import java.util.ArrayList;
//反转链表
public class Solution {
    public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
        ListNode pre = null;
        ListNode cur = listNode;
        ListNode tmp = cur;
        
        while(cur != null)
        {
            tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        ArrayList<Integer> res = new ArrayList<>();
        while(pre != null)
        {
            res.add(pre.val);
            pre = pre.next;
        }
        return res;
    }
}

JZ4

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KRQnxYDM-1613060635655)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20210128222003593.png)]

/**
 * Definition for binary tree
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
import java.util.Arrays;
//使用递归的方式求解
public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        if(pre.length == 0 || in.length == 0)
            return null;
        //当前子树根节点
        TreeNode root = new TreeNode(pre[0]);
        
        for(int i = 0; i < in.length; i++)
        {
            if(in[i] == pre[0])
            {
                root.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i+1),
                                                  Arrays.copyOfRange(in , 0, i));
                root.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i+1 , pre.length),
                                                  Arrays.copyOfRange(in, i+1, in.length));
            }
        }
        
        return root;
    }
}
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* reConstructBinaryTree(vector pre,vector vin) {
        if(pre.size() == 0 || vin.size() == 0)
            return nullptr;
        struct TreeNode *root = new TreeNode(pre[0]);
        int N = 0;
        for(int i = 0; i < vin.size() ; i++)
        {
            if(vin[i] == pre[0])
            {
                N = i;
            }
        }
        vector pre_l;
        vector vin_l;
        vector pre_r;
        vector vin_r;
        for(int i = 1; i <= N; i++)
        {
            pre_l.push_back(pre[i]);
        }
        for(int i = 0; i < N; i++)
        {
            vin_l.push_back(vin[i]);
        }
        for(int i = N+1; i < pre.size(); i++)
        {
            pre_r.push_back(pre[i]);
        }
        for(int i = N+1; i < vin.size(); i++)
        {
            vin_r.push_back(vin[i]);
        }
        for(int i = 0; i < vin.size() ; i++)
        {
            if(vin[i] == pre[0])
            {
                root->left = reConstructBinaryTree(pre_l, vin_l);
                root->right = reConstructBinaryTree(pre_r, vin_r);
            }
        }
        return root;
    }
};

//解法2
/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* rebuild(vector pre, int pre_l , int pre_r , vector vin , int vin_l , int vin_r)
    {
        if(pre_l > pre_r)
            return nullptr;
        TreeNode * root = new TreeNode(pre[pre_l]);
        for(int i = vin_l ; i <= vin_r; i++)
        {
            if(vin[i] == root->val)
            {
                root->left = rebuild(pre, pre_l + 1 , pre_l + i - vin_l, vin , vin_l , i - 1);
                root->right = rebuild(pre, pre_l + i - vin_l + 1 , pre_r, vin , i + 1 , vin_r);
            }
        }
        return root;
    }
    TreeNode* reConstructBinaryTree(vector pre,vector vin) {
        return rebuild(pre, 0, pre.size() - 1, vin, 0, vin.size() - 1);
    }
};

JZ5

import java.util.Stack;

public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    public void push(int node) {
        stack1.push(node);
    }
    
    public int pop() {
        if(stack2.empty())
        {
            for(int i = stack1.size() - 1; i >= 0; i--)
            {
                int tmp = stack1.pop();
                stack2.push(tmp);
            }
        }
        int res = stack2.get(stack2.size() - 1);
        stack2.pop();
        return res;
    }
}

//简洁写法
import java.util.Stack;

public class Solution {
    Stack<Integer> stack1 = new Stack<Integer>();
    Stack<Integer> stack2 = new Stack<Integer>();
    
    public void push(int node) {
        stack1.push(node);
    }
    
    public int pop() {
        if(stack2.empty())
        {
            while(!stack1.empty())
            {
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
}

JZ6

//二分查找
import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        int begin = 0 , end = array.length - 1;
        while(begin < end)
        {
            int mid = (begin + end) / 2;
            if(array[mid] > array[end])
            {
                begin = mid + 1;
            }
            else if(array[mid] < array[end])
            {
                end = mid;
            }
            else if(array[mid] == array[end])
            {
                end--;
            }
        }
        return array[begin];
    }
}

JZ7

//记忆化搜索
class Solution {
public:
    int Fib(int n , vector & dp)
    {
        if(n == 0 || n == 1) return n;
        if(dp[n] != -1) return dp[n];
        return dp[n] = Fib(n-1, dp) + Fib(n-2,dp);
    }
    int Fibonacci(int n) {
       vector dp(45 , -1);
       return Fib(n , dp);
    }
};

//动态规划
class Solution {
public:
    int Fibonacci(int n) {
        vector dp(n+1 , 0);
        dp[1] = 1;
        for(int i = 2; i <= n; i++)
        {
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[n];
    }
};
public class Solution {
    public int Fibonacci(int n) {
        if(n == 0 || n == 1) return n;
        return Fibonacci(n-1) + Fibonacci(n-2);
    }
}

JZ8/JZ9

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lWiQm3C3-1613060635663)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20210127215149118.png)]

public class Solution {
    public int JumpFloorII(int target) {
        if(target == 1 || target == 0) return 1;
        int[] res = new int[target+1];
        res[0] = res[1] = 1;
        for(int i = 2; i <= target; i++)
        {
            res[i] = 0;
            for(int j = 0; j < i; j++)
            {
                res[i] += res[j];
            }
        }
        return res[target];
    }
}

public class Solution {
    public int JumpFloorII(int target) {
        if(target == 1 || target == 0) return 1;
        int[] res = new int[target+1];
        res[0] = res[1] = 1;
        for(int i = 2; i <= target; i++)
        {
            res[i] = 2 * res[i-1];
        }
        return res[target];
    }
}

JZ10

//备忘录
public class Solution {
    public int rectCover(int target) {
        if(target < 3)
            return target;
        int[] res = new int[target+1];
        res[0] = 0;
        res[1] = 1;
        res[2] = 2;
        for(int i = 3; i <= target ; i++)
        {
            res[i] = res[i-1] + res[i-2];
        }
        return res[target];
    }
}

JZ11

二进制中1的个数

如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。

//普通方法
public class Solution {
    public int NumberOf1(int n) {
        int mark = 0x01;
        int res = 0;
        while(mark != 0)
        {
            if((n & mark) != 0) res++;
            mark <<= 1;
        }
        return res;
    }
}
//技巧法 n与n-1做与运算
public class Solution {
    public int NumberOf1(int n) {
        int res = 0;
        while(n != 0)
        {
           n = n & (n - 1);
           res++;
        }
        return res;
    }
}

JZ12

//自己编写函数实现
public class Solution {
    public double Power(double base, int exponent) {
        double res = 1.0;
        if(exponent < 0)
        {
            base = 1 / base;
            exponent = - exponent;
        }
        for(int i = 0; i < exponent; i++)
        {
            res *= base;
        }
        return res;
  }
}
//调用库函数
public class Solution {
    public double Power(double base, int exponent) {
        double res = Math.pow(base, exponent);
        return res;
  }
}

JZ13

//开辟新数组
public class Solution {
    public void reOrderArray(int [] array) {
        int[] res = new int[array.length];
        int j = 0;
        for(int i = 0 ; i < array.length ; i++)
        {
            if(array[i] % 2 == 1)
            {
                res[j] = array[i];
                j++;
            }
        }
        for(int i = 0; i < array.length; i++)
        {
            if(array[i] % 2 == 0)
            {
                res[j] = array[i];
                j++;
            }
        }
        for(int i = 0 ; i < array.length; i++)
        {
            array[i] = res[i];
        }
    }
}
//不开辟数组,使用双指针进行移动替换
public class Solution {
    public void reOrderArray(int [] array) {
        int i = 0;
        for(int j = 0; j < array.length; j++)
        {
            if(array[j] % 2 == 1)
            {
                int tmp = array[j];
                //必须从后往前填充,否则会覆盖
                for(int m = j-1;m >= i; m--)
                {
                    array[m+1] = array[m];
                }
                array[i++] = tmp;
            }
        }
    }
}

JZ14

  • 输入一个链表,输出该链表中倒数第k个结点
  • 倒数第k个结点为整数第total-k+1个结点
//普通解法
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        if(head == null || k <= 0) return null;
        int total = 1; 
        ListNode cur = head.next;
        while(cur != null)
        {
            cur = cur.next;
            total++;
        }
        if(total < k) return null;
        ListNode res = head;
        for(int i = 1; i < total - k + 1; i++)
        {
            res = res.next;
        }
        return res;
    }
}
  • 快慢指针求解: 让快指针先走k步,当快指针指向空时,慢指针指向的变量即为返回值;
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        if(head == null || k <= 0) return null;
        ListNode fast = head;
        ListNode slow = head;
        for(int j = 0;j < k; j++)
        {
            //考虑顺序
            if(fast == null) return null;
            fast = fast.next;
        }
        while(fast != null)
        {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;        
    }
}

JZ15

  • 反转链表
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
        if(head == null) return null;
        ListNode cur = head;
        ListNode pre = null;
        ListNode tmp = null;
        while(cur != null)
        {
            tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
}

JZ16

  • 合并两个排序的链表
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        if(list1 == null && list2 == null) return null;
        ListNode h = new ListNode(-1);
        ListNode cur = h;
        
        while(list1 != null && list2 != null)
        {
            if(list1.val < list2.val)
            {
                cur.next = list1;
                list1 = list1.next;
            }
            else if(list1.val >= list2.val)
            {
                cur.next = list2;
                list2 = list2.next;
            }
            cur = cur.next;
        }
        cur.next = (list1 == null) ? list2 : list1;
        return h.next;
    }
}
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        if(list1 == null && list2 == null) return null;
        ListNode head = new ListNode(-1);
        ListNode cur = head;
        while(list1 != null && list2 != null)
        {
            if(list1.val <= list2.val)
            {
                cur.next = list1;
                list1 = list1.next;
            }
            else{
                cur.next = list2;
                list2 = list2.next;
            }
            cur = cur.next;
        }
        if(list1 != null) cur.next = list1;
        if(list2 != null) cur.next = list2;
        return head.next;
    }
}
//递归写法
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        if(list1 == null && list2 == null) return null;
        //递归
        if(list1 == null) return list2;
        if(list2 == null) return list1;
        
        if(list1.val <= list2.val)
        {
            list1.next = Merge(list1.next, list2);
            return list1;
        }
        else{
            list2.next = Merge(list1,list2.next);
            return list2;
        }
    }
}

JZ17

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    //写一个方法,传入两颗根节点值相同的树,判断tree1 , tree2的结构是否一样
    public boolean doesTreeHasTree2(TreeNode tree1 , TreeNode tree2)
    {
        if(tree2 == null) return true;
        if(tree1 == null) return false;
        if(tree1.val != tree2.val)
            return false;
        return doesTreeHasTree2(tree1.left , tree2.left) 
                && doesTreeHasTree2(tree1.right , tree2.right);
    }
    //遍历大树,找到一个和小树根结点值相等的结点,
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if(root2 == null || root1 == null)
            return false;
        return doesTreeHasTree2(root1,root2) || HasSubtree(root1.left, root2)
               || HasSubtree(root1.right, root2);
    }
}
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if(root1 == null || root2 == null)
            return false;
        if(root1.val == root2.val)
        {
            if(judge(root1, root2))
                return true;
        }
        //遍历左右孩子
        return HasSubtree(root1.left , root2) || HasSubtree(root1.right , root2);
    }
    public boolean judge(TreeNode tree1, TreeNode tree2)
    {
        //子循环已循环完毕,代表全部匹配
        if(tree2 == null) return true;
        //大树循环完毕,并未成功匹配
        if(tree1 == null) return false;
        //相等后判断左右孩子
        if(tree1.val == tree2.val)
        {
            return judge(tree1.left, tree2.left) && judge(tree1.right, tree2.right);
        }
        return false;
    }
}
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public boolean judge(TreeNode t1 , TreeNode t2)
    {
        if(t2 == null) return true;
        if(t1 == null) return false;
        if(t1.val == t2.val)
        {
            return judge(t1.left, t2.left) && judge(t1.right , t2.right);
        }
        return false;
    }
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if(root1 == null || root2 == null) return false;
        if(root1.val == root2.val)
        {
            //judge失败则进入递归调用
            if(judge(root1,root2))
                return true;
        }
        return HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);
    }
}

JZ18

  • 二叉树镜像
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    //考察后序遍历 从树结点底部向上交换
    public TreeNode dfs(TreeNode tree)
    {
        if(tree == null) return null;
        TreeNode ltree = dfs(tree.left);
        TreeNode rtree = dfs(tree.right);
        tree.left = rtree;
        tree.right = ltree;
        return tree;
    }
    public void Mirror(TreeNode root) {
        if(root == null) return;
        root = dfs(root);
    }
}
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public TreeNode dfs(TreeNode r)
    {
        if(r == null) return null;
        TreeNode ltree = dfs(r.left);
        TreeNode rtree = dfs(r.right);
        r.right = ltree;
        r.left = rtree;
        return r;
    }
    public void Mirror(TreeNode root) {
        if(root == null) return ;
        dfs(root);
    }
}

JZ19

  • 顺时针打印矩阵
// ??
import java.util.ArrayList;
public class Solution {
    
    public void printCircle(ArrayList<Integer> res,int[][] matrix ,int lx, int ly , int rx , int ry)
    {
        for(int i = ly; i <= ry; i++)
        {
            res.add(matrix[lx][i]);
        }
        for(int i = lx+1; i <= rx; i++)
        {
            res.add(matrix[i][ry]);
        }
        //只有一行,不需要第三步
        int h = rx - lx + 1;
        if(h > 1)
        {
            for(int i = ry - 1 ; i >= ly; i--)
            {
                res.add(matrix[rx][i]);
            }
        }
        //只有一列,不需要第失败
        int w = ry - ly + 1;
        if(w > 1)
        {
            for(int i = rx - 1; i > lx; i--)
            {
                res.add(matrix[i][ly]);
            }
        }

    }
    public ArrayList<Integer> printMatrix(int [][] matrix) {
        
        ArrayList<Integer> res = new ArrayList<>();
        if(matrix.length == 0) return res;
        int lx = 0, ly = 0, rx = matrix.length - 1, ry = matrix[0].length - 1;
        while(lx <= rx && ly <= ry)
        {
            printCircle(res, matrix , lx++, ly++ , rx-- , ry--);
        }
        return res;
    }
}
//秒
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> printMatrix(int [][] matrix) {
       ArrayList<Integer> res = new ArrayList<>();
       if(matrix == null || matrix.length == 0 || matrix[0].length == 0) return res;
       
        int up = 0;
        int down = matrix.length - 1;
        int left = 0;
        int right = matrix[0].length - 1;
        
        while(true)
        {
            for(int col = left; col <= right; col++)
                res.add(matrix[up][col]);
            up++;
            if(up > down)
                break;
            for(int row = up; row <= down; row++)
                res.add(matrix[row][right]);
            right--;
            if(left > right)
                break;
            for(int col = right; col >= left; col--)
                res.add(matrix[down][col]);
            down--;
            if(up > down)
                break;
            for(int row = down; row >= up; row--)
                res.add(matrix[row][left]);
            left++;
            if(left > right)
                break;
        }
       return res;
    }
}

JZ20

  • 包含min函数的栈
  • 开辟一个辅助栈来专门获取最小值;
import java.util.Stack;

public class Solution {
    private static Stack<Integer> normal = new Stack<Integer>();
    private static Stack<Integer> minval = new Stack<Integer>();
    
    public void push(int node) {
        normal.push(node);
        if(minval.empty())
        {
            minval.push(node);
        }
        else{
            if(node < minval.peek())
            {
                minval.push(node);
            }else{
                minval.push(minval.peek());
            }
        }
    }
    
    public void pop() {
        normal.pop();
        minval.pop();
    }
    
    public int top() {
        return normal.peek();
    }
    
    public int min() {
        return minval.peek();
    }
}

JZ21

  • 栈的压入,弹出序列
import java.util.ArrayList;
import java.util.Stack;

public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
        Stack<Integer> stack = new Stack<>();
        int j = 0;
        for(int i = 0; i < pushA.length; i++)
        {
            stack.push(pushA[i]);
            while(!stack.isEmpty() && stack.peek() == popA[j])
            {
                stack.pop();
                j++;
            }
        }
        return stack.isEmpty();
    }
}

JZ22

  • 从上往下打印二叉树
  • 层序遍历,使用队列实现,将根结点放入队列中,每次打印一个结点值后判断是否有左右子结点,有则将其加入队列中
import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> array = new ArrayList<>();
        Deque<TreeNode> deque = new LinkedList<>();
        if(root == null) return array;

        deque.add(root);
        while(!deque.isEmpty()){
            TreeNode node = deque.getFirst();
            deque.pollFirst();
            array.add(node.val);
            
            if(node.left != null)
                deque.addLast(node.left);
            if(node.right != null)
                deque.addLast(node.right);
        }
        return array;
    }
}

JZ23

  • 二叉搜索树的后序遍历序列
  • 二叉搜索树:左子树的值小于根结点,右子树的值大于根结点
public class Solution {
    public boolean VerifySquenceOfBST(int [] sequence) {
        if(sequence == null || sequence.length == 0)
            return false;
        
        return isBFS(sequence, 0 , sequence.length - 1);
    }
    private boolean isBFS(int[] seq ,int start, int end)
    {
        if(end - start <= 1)
            return true;
        int rootVal = seq[end];
        int cutIndex = start;
        while(cutIndex < end && seq[cutIndex] <= rootVal)
            cutIndex++;
        for(int i = cutIndex; i < end; i++)
            if(seq[i] < rootVal)
                return false;
        return isBFS(seq , start , cutIndex-1) && 
                     isBFS(seq, cutIndex , end - 1);
    }
}

JZ24

  • 二叉树中和为某一值的路径
import java.util.ArrayList;
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val) {
        this.val = val;
    }

}
*/
public class Solution {
    private ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
    
    
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
        backtracking(root , target , new ArrayList<Integer>());
        return ret;
    }
    
    private void backtracking(TreeNode node , int target , ArrayList<Integer> path)
    {
        if(node == null)
            return ;
        path.add(node.val);
        target -= node.val;
        if(target == 0 && node.left == null && node.right == null)
        {
            ret.add(new ArrayList<>(path));
        }
        else{
            backtracking(node.left , target , path);
            backtracking(node.right , target , path);
        }
        path.remove(path.size() - 1);
    }
}

JZ25

  • 复杂链表的复制
//使用HashMap
/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
import java.util.HashMap;

public class Solution {
    public RandomListNode Clone(RandomListNode pHead)
    {
        if(pHead == null) return null;
        
        RandomListNode target = new RandomListNode(pHead.label);
        RandomListNode cur = pHead;
        RandomListNode p = target;    //获取新链表表头
        HashMap<RandomListNode, RandomListNode> map = new HashMap<>();
        
        while(pHead != null)
        {
            map.put(pHead , new RandomListNode(pHead.label));
            pHead = pHead.next;
        }
        //target作为新链表的头,由cur, p移动来复制链表
        while(cur != null)
        {
            p.next = map.get(cur.next);
            p.random = map.get(cur.random);
            
            cur = cur.next;
            p = p.next;
        }
        return target;
    }
}
//第二种形式

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
import java.util.HashMap;

public class Solution {
    public RandomListNode Clone(RandomListNode pHead)
    {
        HashMap<RandomListNode , RandomListNode> map = new HashMap<>();
        RandomListNode p = pHead;
        //第一次遍历,建立新结点
        while(p != null)
        {
            map.put(p , new RandomListNode(p.label));
            p = p.next;
        }
        //第二次遍历,赋值映射关系
        p = pHead;
        while(p != null)
        {
            RandomListNode node = map.get(p);
            node.next = (p.next == null) ? null : map.get(p.next);
            node.random = (p.random == null) ? null : map.get(p.random);
            p = p.next;
        }
        return map.get(pHead);
    }
}
//不使用HashMap
/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
public class Solution {
    public RandomListNode Clone(RandomListNode pHead)
    {
        if(pHead == null) return null;
        //插入新结点
        RandomListNode cur = pHead;
        while(cur != null)
        {
            RandomListNode clone = new RandomListNode(cur.label);
            clone.next = cur.next;
            cur.next = clone;
            cur = clone.next;
        }
        //建立random连接
        cur = pHead;
        while(cur != null)
        {
            RandomListNode clone = cur.next;
            if(cur.random != null)
                clone.random = cur.random.next;
            cur = clone.next;
        }
        //拆分
        cur = pHead;
        RandomListNode pCloneHead = pHead.next;
        while(cur.next != null)
        {
            RandomListNode next = cur.next;
            cur.next = next.next;
            cur = next;
        }
        return pCloneHead;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hyf7B4lB-1613060635669)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20210131090251749.png)]

JZ26

  • 二叉搜索树与双向链表
//先中序遍历存储到数组列表中,然后遍历数组列表更改指针指向(有问题,开辟了新的内存)
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.ArrayList;

public class Solution {
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null)
            return null;
        ArrayList<TreeNode> list = new ArrayList<>();
        Convert(pRootOfTree, list);
        return  Convert(list);        
    }
    //中序遍历
    public void Convert(TreeNode pRootOfTree, ArrayList<TreeNode> list)
    {
        if(pRootOfTree.left != null)
            Convert(pRootOfTree.left , list);
        list.add(pRootOfTree);
        if(pRootOfTree.right != null)
            Convert(pRootOfTree.right , list);        
    }
    //遍历list,修改指针
    public TreeNode Convert(ArrayList<TreeNode> list)
    {
        for(int i = 0; i < list.size() - 1; i++)
        {
            list.get(i).right = list.get(i+1);
            list.get(i+1).left = list.get(i);
        }
        return list.get(0);
    }
    
}
//线索化二叉树
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    TreeNode pre = null;
    TreeNode root = null;
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null)
            return null;
        Convert(pRootOfTree.left);
        if(root == null)
            root = pRootOfTree;
        if(pre != null)
        {
            pRootOfTree.left = pre;
            pre.right = pRootOfTree;
        }
        pre = pRootOfTree;
        Convert(pRootOfTree.right);
        return root;
    }
}
/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    private TreeNode pre =null;
    private TreeNode head = null;
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null)
            return null;
        Convert(pRootOfTree.left);
        //处理
        pRootOfTree.left = pre;
        if(pre != null)
            pre.right = pRootOfTree;
        pre = pRootOfTree;    //更新pre
        
        if(head == null)
            head = pRootOfTree;
        
        Convert(pRootOfTree.right);
        
        return head;
    }
}

JZ27

  • 字符串的全排列
  • 考察回溯算法决策树
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
    private ArrayList<String> ret = new ArrayList<>();
    
    public ArrayList<String> Permutation(String str) {
       if(str.length() == 0)
           return ret;
        char[] chars = str.toCharArray();
        Arrays.sort(chars);
        backtracking(chars , new boolean[chars.length] , new StringBuilder());
        return ret;
    }
    
    private void backtracking(char[] chars , boolean[] hasUsed , StringBuilder s)
    {
        if(s.length() == chars.length){
            ret.add(s.toString());
            return;
        }
        for(int i = 0; i < chars.length; i++)
        {
            if(hasUsed[i])
                continue;
            if(i != 0 && chars[i] == chars[i-1] && !hasUsed[i-1])
                continue;
            hasUsed[i] = true;
            s.append(chars[i]);
            backtracking(chars,hasUsed , s);
            s.deleteCharAt(s.length() - 1);
            hasUsed[i] = false;
        }
    }
    
}
class Solution {
public:
    
    void perm(int pos , string s , set &ret)
    {
        if(pos + 1 == s.length())
        {
            ret.insert(s);
            return;
        }
        for(int i = pos ; i < s.length(); i++)
        {
            swap(s[pos] , s[i]);
            perm(pos+1 , s , ret);
            swap(s[pos] , s[i]);    //回溯
        }
    }
    
    vector Permutation(string str) {
        if(str.empty()) return {};
        set ret;
        perm(0, str , ret);
        return vector({ret.begin(), ret.end()});        
    }
};
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
    public ArrayList<String> res = new ArrayList<>();
    
    public void backtracking(char[] chars, boolean[] hasUsd, StringBuilder s)
    {
        if(s.length() == chars.length)
        {
            res.add(s.toString());
            return;
        }
        
        for(int i = 0; i < chars.length; i++)
        {
            if(hasUsd[i])
                continue;
            
            //判断是否有重复字母
            if(i != 0 && chars[i] == chars[i-1] && hasUsd[i-1])
                continue;
            s.append(chars[i]);
            hasUsd[i] = true;
            backtracking(chars, hasUsd , s);
            s.deleteCharAt(s.length() - 1);
            hasUsd[i] = false;
        }        
    }
    
    public ArrayList<String> Permutation(String str) {
        char[] chars = str.toCharArray();
        Arrays.sort(chars);
        backtracking(chars , new boolean[chars.length] , new StringBuilder());
        return res;
    }
}

JZ28

  • 数组中出现次数超过一半的数字

  1. 使用HashMap对数组中元素出现的次数进行记录
import java.util.HashMap;

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        HashMap<Integer, Integer> mp = new HashMap<>();
        for(int e : array)
        {
            if(mp.containsKey(e))
            {
                
                mp.put(e, mp.get(e) + 1);
            }
            else{
                mp.put(e,1);                
            }
        }
        for(int e : array)
        {
            if(mp.get(e) > array.length / 2) return e;
        }
        return 0;
    }
}

  • 排序法:首先将数组排序,可能的众数肯定在数组中间
import java.util.Arrays;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        Arrays.sort(array);
        int cond = array[array.length / 2];
        
        int cnt = 0;
        for(int e : array)
        {
            if(e == cond) cnt++;
        }
        if(cnt > array.length / 2) return cond;
        
        return 0;        
    }
}

  • 候选人法: 假如数组中存在众数,那么众数一定大于数组的长度的一半,如果2个数不相等,就消去这2个数,最坏情况,每次消去一个众数和非众数,最后留下的肯定是众数;
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        int cond = -1;
        int cnt = 0;
        for(int i = 0; i < array.length; i++)
        {
            if(cnt == 0)
            {
                cond = array[i];
                ++cnt;
            }else{
                if(cond == array[i]) ++cnt;
                else --cnt;
            }
        }
        cnt = 0;
        for(int e : array)
            if(cond == e) ++cnt;
        if(cnt > array.length / 2) return cond;
        return 0;
    }
}
public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        int cond = -1;
        int cnt = 0;
        for(int e : array)
        {
            if(cnt == 0)
            {
                cond = e;
                cnt++;
            }else
            {
                if(cond == e) cnt++;
                else cnt--;
            }
        }
        //判断是否为众数
        cnt = 0;
        for(int e : array)
        {
            if(cond == e) cnt++;
        }
        if(cnt > array.length / 2) return cond;
        
        return 0;
    }
}

JZ29

  • 最小的k个数

  1. 使用堆排序(大顶堆,使用优先队列)
import java.util.PriorityQueue;
import java.util.ArrayList;
import java.util.Comparator;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        if(k > input.length || k < 0)
            return new ArrayList<>();
        //创建大顶堆
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(new Comparator<Integer>(){
            public int compare(Integer o1, Integer o2)
            {
                return o2 - o1;
            }
        });
        for(int i = 0; i < input.length ; i++)
        {
            maxHeap.add(input[i]);
            if(maxHeap.size() > k)
                maxHeap.poll();    //弹出最大值
        }
        return new ArrayList<>(maxHeap);
    }
}
import java.util.ArrayList;
import java.util.PriorityQueue;

public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        if(k > input.length || k < 0) return new ArrayList<>();
        //使用lamada表达式
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>((o1,o2)->o2 - o1);
        for(int i = 0; i < input.length; i++)
        {
            maxHeap.add(input[i]);
            if(maxHeap.size() > k)
            {
                maxHeap.poll();
            }
        }
        return new ArrayList<>(maxHeap);
    }
}

自己实现大顶堆结构:

建立最大堆时是从最后一个非叶子结点开始从下往上进行调整的

import java.util.ArrayList;

public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> list = new ArrayList<>();
        if(input == null || input.length == 0 || k > input.length || k == 0)
            return list;
        int[] arr = new int[k+1];    //数组下标0的位置作为下标,不存储数据
        //初始化数组
        for(int i = 1; i < k + 1; i++)
        {
            arr[i] = input[i-1];
        }
        buildMaxHeap(arr,k+1);
        for(int i = k; i < input.length; i++)
        {
            if(input[i] < arr[1])
            {
                arr[1] = input[i];
                adjustDown(arr,1,k+1);
            }
        }
        for(int i = 1; i < arr.length; i++)
            list.add(arr[i]);
        return list;
    }
    public void buildMaxHeap(int[] arr, int length)
    {
        if(arr == null || arr.length == 0 || arr.length == 1)
            return;
        for(int i = (length - 1)/2; i > 0; i--)
            adjustDown(arr,i , arr.length);
    }
    //堆排序中对一个子二叉树排序
    public void adjustDown(int[] arr, int k , int length)
    {
        arr[0] = arr[k];
        for(int i = 2 * k; i <= length; i *= 2)
        {
            if(i < length - 1 && arr[i] < arr[i + 1])
                i++;
            if(i > length - 1 || arr[0] >= arr[i])
                break;
            else{
                arr[k] = arr[i];
                k = i;
            }
        }
        arr[k] = arr[0];
    }   
}

  • 使用自带的排序
import java.util.ArrayList;
import java.util.Arrays;
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        if(k > input.length || k < 0) return new ArrayList<>();
        Arrays.sort(input);
        ArrayList<Integer> res = new ArrayList<>();
        for(int i = 0 ; i < k ; i++)
        {
            res.add(input[i]);
        }
        return res;
    }
}
import java.util.ArrayList;

public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> res = new ArrayList<>();
        if(input == null || input.length == 0 || k > input.length || k <= 0)
            return res;
        for(int i = input.length; i > 0; i--)
        {
            buildMaxHeap(input,i);
            Swap(input,i);
        }
        for(int i = 0; i < k; i++)
        {
            res.add(input[i]);
        }
        return res;
    }
    public void buildMaxHeap(int[] arr, int len)
    {
        for(int i= len / 2 - 1; i >= 0; i--)
        {
            if(2*i+1 < len && arr[i] < arr[2*i+1])
            {
                int tmp = arr[i];
                arr[i] = arr[2*i+1];
                arr[2*i+1] = tmp;
                if(2*(2*i+1) + 1 < len && arr[2*i+1] < arr[2*(2*i+1)+1] ||
                   2*(2*i+1) + 2 < len && arr[2*i+1] < arr[2*(2*i+1)+2])
                {
                    buildMaxHeap(arr,len);
                }
            }
            if(2*i+2 < len && arr[i] < arr[2*i+2])
            {
                int tmp = arr[i];
                arr[i] = arr[2*i+2];
                arr[2*i+2] = tmp;
                if(2*(2*i+2) + 1 < len && arr[2*i+2] < arr[2*(2*i+2)+1] ||
                   2*(2*i+2) + 2 < len && arr[2*i+2] < arr[2*(2*i+2)+2])
                {
                    buildMaxHeap(arr,len);
                }
            }
        }
    }
    private void Swap(int[] in, int len)
    {
        int tmp = in[0];
        in[0] = in[len-1];
        in[len-1] = tmp;
    }
}

JZ30

  • 连续子数组的最大和


    使用动态规划:

    最大子数组的和一定是由当前元素和之前最大连续子数组的和叠加在一起形成的;

import java.lang.Math;
public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        if(array == null || array.length == 0)
            return 0;
        int[] dp = new int[array.length + 1];        
        int ret = array[0];
        for(int i = 1; i <= array.length ; ++i)
        {
            dp[i] = Math.max(array[i-1],dp[i-1]+array[i-1]);
            ret = Math.max(ret, dp[i]);
        }
        return ret;
    }
}
public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        if(array == null || array.length == 0)
            return 0;
        int greatestSum = Integer.MIN_VALUE;
        int sum = 0;
        for(int val : array)
        {
            sum = sum <= 0 ? val : sum + val;
            greatestSum = Math.max(greatestSum,sum);
        }
        return greatestSum;
    }
}
public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        int max = array[0];
        for(int i = 1; i < array.length; i++)
        {
            array[i] += array[i-1] > 0 ? array[i-1] : 0;
            max = Math.max(max,array[i]);
        }
        return max;
    }
}
public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {
        int[] dp = new int[array.length];
        int max = array[0];
        dp[0] = array[0];
        for(int i = 1; i < array.length; i++)
        {
            int newMax = dp[i-1] + array[i];
            dp[i] =  newMax > array[i] ? newMax : array[i];
            if(max < dp[i])
                max = dp[i];
        }
        return max;
    }
}

JZ31

  • 整数中1出现的次数

暴力解法

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        int cnt = 0;
        for(int i = 1; i <= n; i++)
            for(int j = i; j > 0; j /= 10)
                if(j % 10 == 1) cnt++;
        return cnt;
    }
}

找规律:依次求每个位上1出现的次数(考虑密码锁)

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        int high = n / 10;
        int cur = n % 10;
        int low = 0 , digit = 1;
        int res = 0;
        while(high != 0 || cur != 0)
        {
            if(cur == 0) res += high * digit;
            else if(cur == 1) res += (high * digit + low + 1);
            else res += (high * digit + digit);
            //更新
            low += cur * digit;
            cur = high % 10;
            high = high / 10;
            digit *= 10;            
        }
        return res;
    }
}

JZ32

  • 把数组排成最小的树;

将数组转化为字符串,如果a+b < b+a ; 则将其进行交换;

import java.util.ArrayList;
import java.lang.Integer;
public class Solution {
    public String PrintMinNumber(int [] numbers) {
        if(numbers == null || numbers.length == 0)
            return "";
        for(int i = 0; i < numbers.length; i++){
            for(int j = i + 1; j < numbers.length; j++)
            {
                int sum1 = Integer.valueOf(numbers[i] + "" + numbers[j]);
                int sum2 = Integer.valueOf(numbers[j] + "" + numbers[i]);
                if(sum1 > sum2){
                    int tmp = numbers[j];
                    numbers[j] = numbers[i];
                    numbers[i] = tmp;
                }
            }
        }
        String str = new String("");
        for(int i = 0; i < numbers.length; i++)
        {
            str = str + numbers[i];
        }
        return str;
    }
}

JZ33

  • 丑数

第n个丑数: 使用动态规划

class Solution {
    public int nthUglyNumber(int n) {
        if(n <= 0 )
            return 0;
        int a = 0, b = 0, c = 0;
        int[] dp = new int[n];
        dp[0] = 1;
        for(int i = 1; i < n ; i++)
        {
            int n2 = dp[a] * 2 , n3 = dp[b] * 3 , n5 = dp[c] * 5;
            dp[i] = Math.min(Math.min(n2, n3) , n5);
            if(dp[i] == n2) a++;
            if(dp[i] == n3) b++;
            if(dp[i] == n5) c++;
        }
        return dp[n-1];
    }

}

JZ34

  • 第一个只出现一次的字符

使用HashMap对字符出现的次数进行存储,然后再次进行遍历,返回只出现1次的字符

map.keySet().contains© : 检测map中是否包含该键值

import java.util.HashMap;
public class Solution {
    public int FirstNotRepeatingChar(String str) {
        //使用Hashmap
        HashMap<Character, Boolean> map = new HashMap<>();
        char[] sc = str.toCharArray();
        
        for(char c : sc)
        {
            map.put(c, !map.containsKey(c));
        }
        for(int i = 0; i < str.length(); i++)
        {
            if(map.get(sc[i]))
                return i;
        }
        return -1;
    }
}
import java.util.HashMap;
public class Solution {
    public int FirstNotRepeatingChar(String str) {
        if(str == null || str.length() == 0)
            return -1;
        HashMap<Character, Integer> map = new HashMap<>();
        char[] sc = str.toCharArray();
        for(char c : sc)
        {
            //检查是否包含某个键
            if(map.keySet().contains(c))
            {
                int tmp = map.get(c);
                map.put(c, tmp + 1);
            }else{
                map.put(c,1);
            }
        }
        for(int i = 0; i < str.length(); i++)
        {
            if(map.get(sc[i]) == 1)
                return i;
        }
        return -1;
    }
}

JZ35

  • 数组中的逆序对

暴力解法:算法复杂度:O(n2),测试用例无法通过

比较的结果没有为以后的比较提供信息

public class Solution {
    public int InversePairs(int [] array) {
        int p = 0;
        for(int i = 0; i < array.length; i++)
        {
            for(int j = i ; j < array.length ; j++)
            {
                if(array[i] > array[j])
                {
                    p++;
                }
            }
        }
        return p%1000000007;
    }
}

使用归并排序方法:注意:cnt必须使用long类型,因为结果很大,int类型无法保存

public class Solution {
    private long cnt = 0;
    private int[] tmp;    //辅助数组
    
    public int InversePairs(int [] array) {
        if(array == null || array.length < 2)
            return 0;
        
        tmp = new int[array.length];
        mergeSort(array, 0 , array.length-1);
        return (int)(cnt % 1000000007);
    }
    
    private void mergeSort(int[] nums, int l , int h)
    {
        if(h - l < 1)
            return;
        int m = l + (h - l) / 2;
        mergeSort(nums , l , m);
        mergeSort(nums , m+1 , h);
        merge(nums, l, m , h);
    }
    private void merge(int[] nums , int l , int m , int h)
    {
        int i = l, j = m + 1 , k = l;
        while(i <= m || j <= h)
        {
            if(i > m)
            {
                tmp[k] = nums[j++];
            }else if(j > h){
                tmp[k] = nums[i++];
            }else if(nums[i] <= nums[j]){
                tmp[k] = nums[i++];
            }else{
                tmp[k] = nums[j++];
                this.cnt += m - i + 1;
            }
            k++;
        }
        for(k = l; k <= h ; k++)
        {
            nums[k] = tmp[k];
        }
    }
}
public class Solution {
    private int[] tmp;    //辅助数组
    private long cnt = 0;
    public int InversePairs(int [] array) {
        if(array == null || array.length < 2)
            return 0;
        tmp = new int[array.length];
        
        mergeSort(array , 0 , array.length - 1);
        
        return (int)(cnt % 1000000007);
        
    }
    private void mergeSort(int[] nums, int left , int right)
    {
        if(left == right)
            return;
        int mid = left + (right - left) / 2;
        mergeSort(nums, left , mid);
        mergeSort(nums, mid+1, right);
        mergeAndCount(nums , left , mid , right);
    }
    private void mergeAndCount(int[] nums , int left , int mid , int right)
    {
        for(int i = left; i <= right ; i++)
        {
            tmp[i] = nums[i];
        }
        int i = left , j = mid + 1 ;
        for(int k = left; k <= right; k++)
        {
            if(i > mid)
            {
                nums[k] = tmp[j++];
            }else if(j > right)
            {
                nums[k] = tmp[i++];
            }else if(tmp[i] <= tmp[j])
            {
                nums[k] = tmp[i++];
            }else
            {
                nums[k] = tmp[j++];
                cnt += (mid - i + 1);
            }
        }
    }
}

JZ36

  • 两个链表的第一个公共结点

设链表1长度为a+c , 链表2长度为b+c , 则两链表循环a+b+c次后可到达末尾:

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode p1 = pHead1 , p2 = pHead2;
        while(p1 != p2){
            p1 = (p1 != null) ? p1.next : pHead2;
            p2 = (p2 != null) ? p2.next : pHead1;
        }
        return p1;
    }
}

JZ37

  • 数字在排序数组中出现的次数

思路:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pc7jdM8q-1613060635677)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20210206151617280.png)]


使用二分查找,查找上下边界:

//利用两次二分法分别确定target的左右边界(左右边界为target值序列的左/右一位,因此最终结果是right-left-1)
class Solution {
    public int search(int[] nums, int target) {
        if(nums.length == 0) {
            return 0;
        }
        //初始左右指针位置
        int i = 0;
        int j = nums.length-1;
        //第一次二分:找right边界
        //这边是“小于等于”,因此当循环结束后,ij不重合,且如果存在target值的话,i的位置就是右边界(target值序列右边第一个大于target值的位置),因为最后一次循环一定是i=mid+1;且此时j指向target
        while(i <= j) {
            int mid = (i+j) >> 1;
            //这里是“小于等于”,目的是为了确定右边界,就是说当mid等于target时,因为不确定后面还有没有target,所以同样需要左边收缩范围
            if(nums[mid] <= target){
                i = mid+1;
            }
            else{
                j = mid-1;
            }
        }
        //在更新right边界值之前,需要判断这个数组中是否存在target,如果不存在(看j指向的位置是不是target,为什么看的是j指针?详见上面的注释)
        if(j>=0&&nums[j] != target){
            return 0;
        }
        int right = i;    //更新right边界
        //重置指针
        i = 0;
        j = nums.length-1;
        //第二次二分:找left边界
        //结束之后,j指向target序列左边第一个小于它的位置,i指向target(经过上面判断,target一定存在)
        while(i <= j) {
            int mid = (i+j) >> 1;
            //这里是“大于等于”,目的是确定左边界,因为就算当mid等于target的时候,因为不确定左边还有没有target,所以同样需要收缩右边界
            if(nums[mid] >= target){
                j = mid-1;
            }
            else{
                i= mid+1;
            }
        }
        //更新左指针
        int left = j;
        return right-left-1;
    }
}
public class Solution {
    public int GetNumberOfK(int [] array , int k) {
       int i = 0, j = array.length - 1;
        //搜索右边界
        while(i <= j){
            int m = (i + j) / 2;
            if(array[m] <= k)
                i = m + 1;
            else
                j = m -1;
        }
        int right = i;
        if(j >= 0 && array[j] != k) return 0;
        //搜索左边界
        i = 0; j = array.length - 1;
        while(i <= j)
        {
            int m = (i + j )/2;
            if(array[m] < k)
            {
                i = m + 1;
            }else{
                j = m - 1;
            }
        }
        int left = j;
        return right - left - 1;
    }
}

JZ38

  • 二叉树的深度

使用深度优先遍历的方法对二叉树进行遍历求解: 对树进行后序遍历;

树的深度等于左子树的深度与右子树的深度中的最大值加1

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public int TreeDepth(TreeNode root) {
        //分治法
        if(root == null)
            return 0;
        int lval = TreeDepth(root.left);
        int rval = TreeDepth(root.right);
        return Math.max(lval , rval) + 1;
    }
}

层序遍历:使用队列的方式实现

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
import java.util.List;
import java.util.LinkedList;
public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root == null) return 0;
        List<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        List<TreeNode> tmp;
        int res = 0;
        while(!queue.isEmpty())
        {
            tmp = new LinkedList<>();
            for(TreeNode node : queue)
            {
                if(node.left != null) tmp.add(node.left);
                if(node.right != null) tmp.add(node.right);
            }
            queue = tmp;
            res++;
        }
        return res;
   }
}

JZ39

  • 平衡二叉树

使用后序遍历+剪枝的方式进行处理:从低至顶

import java.lang.Math;
public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        return recur(root) != -1;
    }
    private int recur(TreeNode root)
    {
        if(root == null)
            return 0;
        int left = recur(root.left);
        if(left == -1) return -1;
        int right = recur(root.right);
        if(right == -1) return -1;
        return Math.abs(left - right) < 2 ? Math.max(left,right) + 1 : -1;
    }
}

使用先序遍历,判断每个节点是否是平衡二叉树:

public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        if(root == null) return true;
        return Math.abs(depth(root.left) - depth(root.right)) <= 1 &&
        IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
    }
    //返回二叉树深度
    private int depth(TreeNode root)
    {
        if(root == null)
            return 0;
        return (Math.max(depth(root.left) , depth(root.right)) + 1);
    }
}

JZ40

  • 数组中只出现1次的数字

方法1:使用Hashmap对数组元素个数进行记录: 时间复杂度为O(n2)

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
import java.util.HashMap;
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for(int e : array)
        {
            if(map.keySet().contains(e))
            {
                map.put(e, map.get(e) + 1);
            }else
            {
                map.put(e,1);
            }
        }
        int flag = 0;
        for(int e : array)
        {
            if(map.get(e) == 1){
                if(flag == 0){
                    num1[0] = e;
                    flag++;
                }
                if(flag == 1)
                    num2[0] = e;
            }
        }
    }
}

异或运算:将数组分为2组进行异或,分组要求:

1.两个只出现一次的数字在不同的组中;

2.相同的数字会被分到相同的组中;

a^b中不为0的位置必然是a,b对应位置不等的元素,可以根据这个来进行分组,使用mask掩码来进行分组;

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int ret = 0;
        for(int n : array)
        {
            ret ^= n;
        }
        int div = 1;
        while((div & ret) == 0)
            div <<= 1;
        int a = 0 , b = 0;
        for(int n : array)
        {
            if((div & n) != 0){
                a ^= n;
            }else{
                b ^= n;
            }
        }
        num1[0] = a;
        num2[0] = b;
    }
}
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        int ret = 0;
        //所有元素进行异或计算
        for(int e : array)
            ret ^= e;
        int mask = 1;
        while((ret & mask) == 0)    //注意运算符优先级
            mask <<= 1;
        num1[0] = num2[0] = 0;
        for(int e : array)
        {
            if((e & mask) == 0)
                num1[0] ^= e;
            else
                num2[0] ^= e;
        }
    }
}

JZ41

  • 和为S的连续正数序列

使用双指针:sum = (l + r) * (r - l + 1) /2 ;

终止条件为:左指针追上右指针;

import java.util.ArrayList;
public class Solution {
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<>();
        if(sum <= 2) return res;
        
        int lp = 1 , rp = 2;
     
        while(lp < rp)
        {
            int s = (lp + rp) * (rp - lp + 1) / 2;
            if(s == sum)
            {
                ArrayList<Integer> tmp = new ArrayList<>();
                for(int i = lp; i <= rp; i++)
                    tmp.add(i);
                res.add(tmp);
                lp++;        //记住更新
            }else if(s < sum){
                rp++;
            }else if(s > sum)
            {
                lp++;
            }
        }
        return res;
    }
}

JZ42

  • 和为S的两个数字

使用对撞双指针,左指针指向数组前面,右指针指向数组末尾

import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
        //对撞双指针
        ArrayList<Integer> ret = new ArrayList<>();
        
        if(array == null || array.length == 0)
            return ret;
        int i = 0, j = array.length - 1;
        
        while(i != j)
        {
            int s = array[i] + array[j];
            if(s == sum)
            {
                ret.add(array[i]);
                ret.add(array[j]);
                break;
            }else if(s < sum)
            {
                i++;
            }else if(s > sum)
            {
                j--;
            }
        }
        return ret;
    }
}

JZ43

  • 左旋字符串

注意n大于字符串长度

public class Solution {
    public String LeftRotateString(String str,int n) {
        if(str == null || str.length() == 0)
            return "";
        if(n > str.length())
            n %= str.length();
        return str.substring(n) + str.substring(0,n);
    }
}

取余~秒

//方法2
public class Solution {
    public String LeftRotateString(String str,int n) {
        StringBuilder ret = new StringBuilder();
        for(int i = n; i < n + str.length(); i++)
        {
            ret.append(str.charAt(i % str.length()));
        }
        return ret.toString();
    }
}

标准解法:先将 “abc” 和 “XYZdef” 分别翻转,得到 “cbafedZYX”,然后再把整个字符串翻转得到 “XYZdefabc”。

public String ReverseSentence(String str) {
    int n = str.length();
    char[] chars = str.toCharArray();
    int i = 0, j = 0;
    while (j <= n) {
        if (j == n || chars[j] == ' ') {
            reverse(chars, i, j - 1);
            i = j + 1;
        }
        j++;
    }
    reverse(chars, 0, n - 1);
    return new String(chars);
}

private void reverse(char[] c, int i, int j) {
    while (i < j)
        swap(c, i++, j--);
}

private void swap(char[] c, int i, int j) {
    char t = c[i];
    c[i] = c[j];
    c[j] = t;
}

JZ44

  • 翻转单词顺序

思路:先翻转每个单词的顺序,再翻转整个字符的顺序

public class Solution {
    public String ReverseSentence(String str) {
        if(str.isEmpty()) return str;
        char[] s = str.toCharArray();
        //先翻转每个单词,再翻转整个字符串
        int i = 0, j = 0;
        while(j <= s.length)
        {
            //最后一个字符没有空格进行分割
            if(j == s.length || s[j] == ' ')
            {
                reverse(s , i , j - 1);
                i = j + 1;
            }
            j++;
        }
        reverse(s , 0 , s.length - 1);
        return new String(s);
    }
    private void reverse(char[] chars , int i , int j)
    {
        while(i < j)
            swap(chars ,i++, j--);
    }
    private void swap(char[] chars , int i , int j)
    {
        char tmp = chars[i];
        chars[i] = chars[j];
        chars[j] = tmp;
    }
}

JZ45

  • 扑克牌顺子

思路:首先对数组排序,其次,统计数组中0的个数,最后统计排序后数组中相邻数字之间的空缺总数。

import java.util.Arrays;

public class Solution {
    public boolean IsContinuous(int [] numbers) {
        if(numbers.length < 5)
            return false;
        //数组排序
        Arrays.sort(numbers);
        //计算癞子树
        int cnt = 0;
        for(int i : numbers)
        {
            if(i == 0)
                cnt++;
        }
        //计算数组空缺
        for(int i = cnt; i < numbers.length - 1; i++)
        {
            if(numbers[i] == numbers[i+1])
                return false;
            cnt -= numbers[i+1] - numbers[i] - 1;
        }
        return cnt >= 0;
    }
}

JZ46

  • 约瑟夫环(孩子们的游戏)

使用递归的方式求解:

f(n, m) = (f(n-1, m) + m) % n; //递推公式推导

public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        if(n <= 0)
            return -1;
        if(n == 1)        //递归终止条件
            return 0;
        return (LastRemaining_Solution(n-1, m) + m) % n;
    }
}

递归可以改成迭代,避免使用栈空间:

f(2) = (f(1) + m) % 2;

f(3) = (f(2) + m) % 3;

f(n) = (f(n-1) + m) % n;

public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        if(n <= 0)
            return -1;
        int f = 0;
        for(int i = 2; i <= n; ++i)
        {
            f = (m + f) % i;
        }
        return f;
    }
}

使用List模拟循环链表

import java.util.List;
import java.util.LinkedList;
public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        if(n < 1 || m < 1)
            return -1;
        List<Integer> list = new LinkedList<>();
        for(int i = 0; i < n; i++)
            list.add(i);
        int cur = -1;		//注意这里是-1
        while(list.size() > 1){
            for(int i = 0; i < m; i++)
            {
                cur++;
                if(cur == list.size())
                    cur = 0;
            }
            list.remove(cur);
            cur--;    //新的list中cur指向了下一个元素
        }
        
        return list.get(0);
    }
}

JZ47

  • 求1+2+3+4…+n

递归解法:

public class Solution {
    public int Sum_Solution(int n) {
        if(n == 1)
            return 1;
        return n + Sum_Solution(n-1);
    }
}

符合题目要求的解法:

利用&&运算符的短路特性

public class Solution {
    public int Sum_Solution(int n) {
        boolean x = n > 0 && (n += Sum_Solution(n-1)) > 0;
        return n;
    }
}

利用||运算符的短路特性:

public class Solution {
    public int Sum_Solution(int n) {
        boolean x =  n < 1 || (n += Sum_Solution(n-1)) > 0;
        return n;
    }
}

特殊思路:

public class Solution {
    int[] test = new int[] {0};
    public int Sum_Solution(int n) {
        try{
            return test[n];
        }catch(Exception e)
        {
            return n + Sum_Solution(n-1);
        }
    }
}

JZ48

  • 不用加减乘除做加法

使用位运算,对二进制的每一位分为无进位和和有进位和2种情况计算;

注意运算符优先级:& 和 <<

public class Solution {
    public int Add(int num1,int num2) {
        while(num2 != 0)    //进位为0时跳出
        {
            int c = (num1 & num2) << 1;      //进位和
            num1 ^= num2;    //非进位和
            num2 = c;
        }
        return num1;
    }
}

写成递归的形式

public class Solution {
    public int Add(int num1,int num2) {
        if(num2 == 0)
            return num1;
        return Add(num1^num2 , (num1 & num2) << 1);
    }
}

JZ49

  • 把字符串转换为整数

public class Solution {
    public int StrToInt(String str) {
        if(str == null || "".equals(str.trim()))
            return 0;
        str = str.trim();
        char[] arr = str.toCharArray();
        int i = 0;
        int flag = 1;
        int res = 0;
        if(arr[i] == '-'){
            flag = -1;
        }
        if(arr[i] == '+' || arr[i] == '-')
            i++;
        while(i < arr.length)
        {
            if(isNum(arr[i])){
                int cur = arr[i] - '0';
                if(flag == 1 && res > Integer.MAX_VALUE / 10
                  || res == Integer.MAX_VALUE/10 && cur > 7)
                {
                    return 0;
                }
                if(flag == -1 && (res > Integer.MAX_VALUE/10) ||
                  res == Integer.MAX_VALUE/10 && cur > 8)
                {
                    return 0;
                }
                res = res * 10 + cur;
                i++;
            }else{
                return 0;
            }
        }
        return res * flag;
    }
    public boolean isNum(char c)
    {
        return (c >= '0')&&(c <= '9');
    }
}

简洁写法

public class Solution {
    public int StrToInt(String str) {
        if(str == null || str.length() == 0)
            return 0;
        boolean isNegative = str.charAt(0) == '-';
        int ret = 0;
        for(int i = 0; i < str.length(); i++)
        {
            char c = str.charAt(i);
            if(i == 0 && (c == '+' || c == '-'))
                continue;
            if(c < '0' || c > '9')    //非法输入
                return 0;
            ret = ret * 10 + (c - '0');
        }
        return isNegative ? -ret : ret;
    }
}

JZ50

  • 数组中重复数字

遇到数组考虑排序,这里有重复两个字,考虑map与set;

import java.util.HashMap;
public class Solution {
    // Parameters:
    //    numbers:     an array of integers
    //    length:      the length of array numbers
    //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
    //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
    //    这里要特别注意~返回任意重复的一个,赋值duplication[0]
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        HashMap<Integer , Boolean> tmp = new HashMap<>();
        for(int i = 0 ; i < length; i++)
        {
            if(!tmp.keySet().contains(numbers[i]))
            {
                tmp.put(numbers[i] , false);
            }else{
                duplication[0] = numbers[i];
                return true;
            }
        }
        return false;
    }
}

方法二 : 利用条件:长度为n的数组里所有数字都在0-n-1范围内

牛客上运行会报错

public boolean duplicate(int[] nums, int length, int[] duplication) {
    if (nums == null || length <= 0)
        return false;
    for (int i = 0; i < length; i++) {
        while (nums[i] != i) {
            if (nums[i] == nums[nums[i]]) {
                duplication[0] = nums[i];
                return true;
            }
            swap(nums, i, nums[i]);
        }
    }
    return false;
}

private void swap(int[] nums, int i, int j) {
    int t = nums[i];
    nums[i] = nums[j];
    nums[j] = t;
}

JZ51

  • 构建乘积数组

暴力解法:

import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        ArrayList<Integer> ret = new ArrayList<>();
        for(int i = 0; i < A.length; i++)
        {
            int tmp = 1;
            for(int j = 0; j < A.length; j++)
            {
                if(i == j)
                    continue;
                tmp *= A[j];
            }
            ret.add(tmp);
        }
        int[] res = new int[ret.size()];
        for(int i = 0; i < res.length ; i++)
        {
            res[i] = ret.get(i);
        }
        return res;
    }
}

动态规划思想:减少重复计算,

时间复杂度O(n) , 空间复杂度O(1)

import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] a) {
        if(a.length == 0) return new int[0];
        int[] b = new int[a.length];
        b[0] = 1;
        int tmp = 1;
        for(int i = 1; i < a.length ; i++)
        {
            b[i] = b[i-1] * a[i-1];
        }
        for(int i = a.length - 2; i >= 0; i--)
        {
            tmp *= a[i+1];
            b[i] *= tmp;
        }
        return b;
    }
}

时间复杂度O(n),空间复杂度O(n):

import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        if(A == null || A.length == 0)
            return A;
        int len = A.length;
        //维护2个DP数组
        int[] left = new int[len];
        int[] right = new int[len];
        left[0] = right[len-1] = 1;
        for(int i = 1 ; i< len; i++)
        {
            left[i] = left[i-1] * A[i-1];
        }
        for(int i = len - 2; i >= 0; i--)
            right[i] = right[i+1] * A[i+1];
        int[] ret = new int[len];
        for(int i = 0; i < len; i++)
            ret[i] = left[i] * right[i];
        return ret;
    }
}

简洁写法:

import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        int n = A.length;
        int[] B = new int[n];
        for(int i = 0 , product = 1; i < n; product *= A[i] ,i++)    //从左往右类乘
            B[i] = product;
        for(int i = n-1, product = 1; i >= 0; product *= A[i] , i--)
            B[i] *= product;
        return B;
    }
}

JZ52

  • 正则表达式匹配

考察动态规划

//存在问题的代码!!
public class Solution {
    public boolean match(char[] str, char[] pattern)
    {
        int m = str.length , n = pattern.length;
        //初始化dp数组
        boolean[][] dp = new boolean[m+1][n+1];
        //base case 1 (空串空正则)
        dp[0][0] = true;    //str的0个串, pattern的0个串
        //base case 2 (空串非空正则) str的0个串 , pattern的偶数个字符,偶数位都为*
//         for(int j = 2; j <= n; j += 2)
//             dp[0][j] = (dp[0][j-2] && (pattern[j-1] == '*'));
        for(int i = 1; i <= n; i++)
            if(pattern[i-1] == '*')
                dp[0][i] = dp[0][i-2];
        //动态规划求解
        for(int i = 1; i < m; i++)
            for(int j = 1; j < n; j++)
            {
                //第j个字符是否为通配符*
                if(pattern[j-1] == '*')
                {
                    if(dp[i][j-2]) dp[i][j] = true;
                    else if(dp[i][j-1]) dp[i][j] = true;
                    else if(dp[i-1][j] && str[i-1] == pattern[j-2]) dp[i][j] = true;
                    else if(dp[i-1][j] && pattern[j-2] == '.') dp[i][j] = true;
                }else{
                    if(dp[i-1][j-1] && str[i-1] == pattern[j-1]) dp[i][j] = true;
                    else if(dp[i-1][j-1] && pattern[j-1] == '.') dp[i][j] = true;
                }
            }
        //返回匹配结果
        return dp[m][n];
    }
}
public class Solution {
    public boolean match(char[] str, char[] pattern)
    {
        int m = str.length , n = pattern.length;
        boolean[][] dp = new boolean[m+1][n+1];
        //base case
        dp[0][0] = true;
        for(int j = 2; j <= n; j += 2)
            dp[0][j] = (pattern[j-1] == '*' && dp[0][j-2]);
        //从底向上规划
        for(int i = 1; i <= m; i++)
            for(int j = 1; j <= n; j++)
            {
                //不同条件下的状态转移方程
                if(str[i-1] == pattern[j-1] || pattern[j-1] == '.')
                {
                    dp[i][j] = dp[i-1][j-1];
                }else if(pattern[j-1] == '*')
                {
                    if(str[i-1] == pattern[j-2] || pattern[j-2] == '.')
                    {
                        dp[i][j] |= dp[i][j-1];
                        dp[i][j] |= dp[i-1][j];
                        dp[i][j] |= dp[i][j-2];
                        
                    }else{
                        dp[i][j] = dp[i][j-2];
                    }
                }
            }
        return dp[m][n];
    }
}

JZ53

  • 表示数值的字符串

方法1: 使用正则表达式进行匹配

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DzrC7YTJ-1613060635683)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20210209104633260.png)]

[]  : 字符集合
()  : 分组
?   : 重复 0 ~ 1 次
+   : 重复 1 ~ n 次
*   : 重复 0 ~ n 次
.   : 任意字符
\\. : 转义后的 .
\\d : 数字
public class Solution {
    public boolean isNumeric(char[] str) {
        //使用正则表达式匹配
        if(str == null || str.length == 0)
            return false;
        return new String(str).matches("[+-]?\\d*(\\.\\d+)?([eE][+-]?\\d+)?");
    }
}
public class Solution {
    public boolean isNumeric(char[] str) {
        String pattern = "^[-+]?\\d*(?:\\.\\d*)?(?:[eE][+-]?\\d+)?$";
        String s = new String(str);
        return s.matches(pattern);
        //或者写
        //return Pattern.matches(pattern,s);
    }
}
public class Solution {
    public boolean isNumeric(char[] str) {
        String pattern = "^[+-]?\\d*(?:\\.\\d*)?(?:[eE][+-]?\\d+)?$";
        return new String(str).matches(pattern);
    }
}

方法2:分析数字中各字符出现的次数,列举各种情况进行判断(有限状态机使用)

//尚存在问题
public class Solution {
    public boolean isNumeric(char[] str) {
        if(str == null || str.length == 0)
            return false;
        int cnt1= 0, cnt2= 0, cnt3=0, pos1 = 0,pos2 = 0,pos3 = 0;
        for(int i = 0; i < str.length; i++)
        {
            if(str[i] != 'e' && str[i] != 'E' && !(str[i] >= '0' && str[i] <= '9')
              && str[i] != '.' && str[i] != '+' && str[i] != '-')
            {
                return false;
            }
            if(str[i] == '.'){
                cnt1++;
                pos1 = i;
            }
            if(str[i] == 'e' || str[i] == 'E'){
                cnt2++;
                pos2 = i;
            }
            if(str[i] == '+' || str[i] == '-'){
                cnt3++;
                pos3 = i;
            }
        }
        if(cnt2 >= 2 || cnt1 >= 2 || cnt3 >= 3)    //字符出现次数不能超过限制
            return false;
        if(pos1 > pos2 && cnt2 != 0)
            return false;
        if(str[0] == '+' || str[0] == '-')
            cnt3--;
        if(cnt2 != 0 && str[pos2 + 1] == '+' || str[pos2+1] == '-')
            cnt3--;
        if(cnt3 != 0)
            return false;
        if(cnt2 != 0){
            boolean flag = false;
            for(int i = pos2+1; i < str.length; i++)
            {
                if(str[i] == '+' || str[i] == '-')
                    continue;
                if(str[i] >= '0' && str[i] <= '9'){
                    flag = true;
                    break;
                }
            }
            if(!flag) return false;
        }
        return true;
    }
}

方法3: 特殊思路,利用异常

public class Solution {
    public int StrToInt(String str) {
        Integer res = 0;
        try{
            res = new Integer(str);
        }catch(NumberFormatException e)
        {

        }finally{
            return res;
        }
    }
}

JZ54

  • 字符流中第一个不重复的字符

思路1:使用HashMap或者LinkedHashMap来进行求解

LinkedHashMaap 是有序的,可以减少代码的循环次数



方法2:使用队列与统计数组,只保留“不重复的字符”

统计数组用来统计每个字符穿线的次数

import java.util.LinkedList;
import java.util.Queue;

public class Solution {
    private int[] cnts = new int[128];
    private Queue<Character> queue = new LinkedList<>();
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        cnts[ch]++;
        queue.add(ch);
        while(!queue.isEmpty() && (cnts[queue.peek()] > 1))
            queue.poll();
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        return queue.isEmpty() ? '#' : queue.peek();
    }
}

JZ55

  • 链表中环的入口结点

使用快慢指针进行求解,快指针每次走2步,慢指针每次走一步,当快慢指针相遇后,快指针指向链表头,快慢指针每次各走一步,再次相遇时,即为链表中环的入口

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        if(pHead == null || pHead.next == null)
            return null;
        ListNode slow = pHead , fast = pHead;
        do
        {
            slow = slow.next;
            fast = fast.next.next;
        }while(slow != fast);    //循环直到快慢指针相遇 必须用do...while
        fast = pHead;
        while(slow != fast)
        {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}

JZ56

  • 删除链表中重复的结点

方法1:使用递归

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
        if(pHead == null || pHead.next == null)
            return pHead;
        ListNode next = pHead.next;
        if(pHead.val == next.val){
            while(next != null && pHead.val == next.val)
                next = next.next;
            return deleteDuplication(next);
        }else{
            pHead.next = deleteDuplication(pHead.next);
            return pHead;
        }
    }
}

方法2:使用HashSet保存重复的值,然后重新遍历进行删除

链表使用时要判断是否为空

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
import java.util.HashSet;
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
        if(pHead == null)
            return null;
        //找出相同结点,存入set
        HashSet<Integer> set= new HashSet<>();
        ListNode pre = pHead;
        ListNode cur = pHead.next;
        while(cur != null)
        {
            if(cur.val == pre.val)
                set.add(cur.val);    //集合不会添加重复的元素
            pre = cur;
            cur = cur.next;
        }
        //再根据相同结点删除
        //先删除头部
        while(pHead != null && set.contains(pHead.val))
            pHead = pHead.next;
        if(pHead == null)
            return null;
        //删除中间结点
        pre = pHead;
        cur = pHead.next;
        while(cur != null)
        {
            if(set.contains(cur.val))
            {
                pre.next = cur.next;
                cur = cur.next;
            }else{
                pre = cur;
                cur = cur.next;
            }
        }
        return pHead;
    }
}

方法3: 使用辅助结点,直接进行删除

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
        if(pHead == null || pHead.next == null)
            return pHead;
        //自己构建辅助头结点
        ListNode head = new ListNode(Integer.MIN_VALUE);
        head.next = pHead;
        ListNode pre = head;
        ListNode cur = head.next;
        while(cur != null)
        {
            if(cur.next != null && cur.val == cur.next.val)
            {
                while(cur.next != null && cur.next.val == cur.val)
                    cur = cur.next;
                cur = cur.next;
                pre.next = cur;
            }else{
                pre = cur;
                cur = cur.next;
            }
        }
        return head.next;
    }
}

JZ57

  • 二叉树的下一个结点

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        if(pNode.right != null)
        {
            TreeLinkNode node = pNode.right;
            while(node.left != null)
                node = node.left;
            return node;
        }
        else{
            while(pNode.next != null)
            {
                TreeLinkNode parent = pNode.next;
                if(parent.left == pNode)
                    return parent;
                pNode = pNode.next;
            }
        }
        return null;
    }
}

在使用一个对象之前,需要判断其是否为null

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        if(pNode == null)
            return null;
        if(pNode.right == null)        //叶子结点则向上找
        {
            TreeLinkNode parent = pNode.next;
            while(parent != null && parent.left != pNode)
            {
                pNode = parent;
                parent = parent.next;
            }
            return parent;
        }else{
            //非叶子结点,右子树不为空,向下找
            TreeLinkNode tmp = pNode.right;
            while(tmp != null && tmp.left != null)
                tmp = tmp.left;
            return tmp;
        }
    }
}

JZ58

  • 对称的二叉树

使用递归,画一个对称二叉树进行分析

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        if(pRoot == null)
            return true;
        return isSame(pRoot.left , pRoot.right);
    }
    boolean isSame(TreeNode r1, TreeNode r2)
    {
        if(r1 == null && r2 == null)
            return true;
        else if((r1 == null && r2 != null) || (r1 != null && r2 == null))
            return false;
        if(r1.val == r2.val)
            return isSame(r1.left , r2.right) && isSame(r1.right, r2.left);
        else
            return false;
    }
}
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    boolean isSymmetrical(TreeNode pRoot)
    {
        return isSame(pRoot , pRoot);
    }
    private boolean isSame(TreeNode r1 , TreeNode r2)
    {
        //递归终止条件
        if(r1 == null && r2 == null)
            return true;
        else if((r1 != null && r2 == null) || (r1 == null && r2 != null))
            return false;
        if(r1.val == r2.val)
            return isSame(r1.left , r2.right) && isSame(r1.right , r2.left);
        else
            return false;
    }
}

JZ59

  • 按之字形顺序打印二叉树

套用层序遍历模板:

不需要确定当前遍历到了哪一层:

void bfs()
{
 	vis[] = {0};
    queue pq(start_val);
    while(!pq.empty())
    {
        int cur = pq.front(); pq.pop();
        for(遍历cur所有的相邻结点nex)
        {
            if(nex结点有效 && vis[nex] == 0)
            {
                vis[nex] = 1;
                pq.push(nex);
            }
        }
    }
}

需要确定遍历到了哪一层:

void bfs()
{
    int level = 0;
    vis[] = {0};
    queue pq(original_val);
    while(!pq.empty())
    {
        int sz = pq.size();
        while(sz--)
        {
            int cur = pq.front(); pq.pop();
            for(遍历cur所有的相邻节点nex)
            {
                if(nex节点有效 && vis[nex] == 0)
                {
                    vis[nex] = 1;
                    pq.push(nex);
                }
            }
        }
        level++;
        ...
    }
}

本题java实现:

import java.util.ArrayList;
import java.util.Queue;
import java.util.LinkedList;
import java.util.Collections;
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
        if(pRoot == null) return ret;
        Queue<TreeNode> queue = new LinkedList<>();

        queue.add(pRoot);
        int level = 0;
        while(!queue.isEmpty())
        {
            int sz = queue.size();
            ArrayList<Integer> tmp = new ArrayList<>();
            while(sz-- != 0){
                TreeNode node = queue.poll();
                tmp.add(node.val);
                if(node.left != null) queue.add(node.left);
                if(node.right != null) queue.add(node.right);
            }
            level++;    //层数+1
            if(level % 2 == 0)    //偶数层
                Collections.reverse(tmp);
            ret.add(tmp);
        }
        return ret;
    }

}

JZ60

  • 把二叉树打印成多行

同JZ59

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
        if(pRoot == null)
            return ret;
        Queue<TreeNode> q = new LinkedList<>();
        q.add(pRoot);
        int level = 0;
        while(!q.isEmpty())
        {
            int sz = q.size();
            ArrayList<Integer> tmp = new ArrayList<>();
            while(sz-- > 0)    //单独添加每层元素
            {
                TreeNode node = q.poll();
                tmp.add(node.val);
                if(node.left != null) q.add(node.left);
                if(node.right != null) q.add(node.right);
            }
            level++;    //记录层数在此处无用
            ret.add(tmp);
        }
        return ret;
    }
    
}

JZ61

  • 序列化二叉树

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    private String deserializer;
    String Serialize(TreeNode root) {
        if(root == null)
            return "#";
        //先序遍历
        return root.val + " " + Serialize(root.left) + " " + Serialize(root.right);
  }
    TreeNode Deserialize(String str) {
       deserializer = str;
        return Deserialize();
  }
    private TreeNode Deserialize()
    {
        if(deserializer.length() == 0)
            return null;
        int index = deserializer.indexOf(" ");
        String node = index == -1 ? deserializer : deserializer.substring(0,index);
        deserializer = index == -1 ? "" : deserializer.substring(index + 1);
        
        if(node.equals("#"))
            return null;
        int val = Integer.valueOf(node);
        TreeNode t = new TreeNode(val);
        t.left = Deserialize();
        t.right = Deserialize();
        return t;
    }
}
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    int index = -1;
    String Serialize(TreeNode root) {
        if(root == null)
        {
            return "#";
        }else{
            return root.val + "," + Serialize(root.left) + "," + Serialize(root.right); 
        }
  }
    TreeNode Deserialize(String str) {
       String[] s= str.split(",");
       index++;
       int len = s.length;
        if(index > len)
            return null;
        TreeNode node = null;
        if(!s[index].equals("#")){    //不是叶子结点,继续递归
            node = new TreeNode(Integer.parseInt(s[index]));
            node.left = Deserialize(str);
            node.right = Deserialize(str);
        }
        return node;
  }
}
/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    private int index = -1;
    String Serialize(TreeNode root) {
        //前序遍历
        if(root == null)
            return "#";
        return root.val + "," + Serialize(root.left) + "," + Serialize(root.right);
  }
    TreeNode Deserialize(String str) {
        String[] s = str.split(",");
        //判断是否为 # (空结点)
        index++;
        if(s[index].equals("#"))
            return null;
        //根左右
        TreeNode node = new TreeNode(Integer.parseInt(s[index]));
        node.left = Deserialize(str);
        node.right = Deserialize(str);
        return node;
  }
}

层序遍历实现:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {
    
    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        //层序遍历实现
        if(root == null)
            return "[]";    
        Queue<TreeNode> q = new LinkedList<>();
        StringBuilder s = new StringBuilder();
        s.append("[");
        q.add(root);
        while(!q.isEmpty())
        {
            TreeNode node = q.poll();
            if(node != null)
            {
                s.append(node.val + ",");   //序列化
                q.add(node.left);
                q.add(node.right);
            }else{
                s.append("null,");
            }
                
        }
        s.deleteCharAt(s.length() - 1);
        s.append(']');
        return s.toString();
    }
    
    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if(data.equals("[]"))
            return null;
        String[] s = data.substring(1, data.length()-1).split(","); //字符串分割
        int index = 0;
        Queue<TreeNode> queue = new LinkedList<>();
        TreeNode head = new TreeNode(Integer.parseInt(s[index++]));
        queue.add(head);
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            if(!s[index].equals("null"))
            {
                node.left = new TreeNode(Integer.parseInt(s[index]));
                queue.add(node.left);
            }
            index++;
            if(!s[index].equals("null"))
            {
                node.right = new TreeNode(Integer.parseInt(s[index]));
                queue.add(node.right);
            }
            index++;
        }
        return head;
    }
}

// Your Codec object will be instantiated and called as such:
// Codec codec = new Codec();
// codec.deserialize(codec.serialize(root));

JZ62

  • 二叉搜索树的第k个结点

二叉搜索树的中序遍历:按从小到大的顺序排列(左根右)

中序遍历的倒序:右根左,则其按照从大到小的顺序排列;

/*
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    int cnt = 0;
    TreeNode res;
    TreeNode KthNode(TreeNode pRoot, int k)
    {
        if(pRoot == null)
            return null;
        cnt = k;
        dfs(pRoot);
        return res;
    }
    //二叉搜索树中序遍历即为结果
    void dfs(TreeNode node)
    {
        if(node == null)
            return;
        dfs(node.left);
        if(cnt == 0)
            return;
        cnt--;
        if(cnt == 0)
        {
            res = node;
            return;
        }
        dfs(node.right);
    }

}

JZ63

  • 数据流中的中位数

方法1:使用大顶堆和小顶堆,在数据插入的时候即进行排序

import java.util.Queue;
import java.util.PriorityQueue;
public class Solution {
    Queue<Integer> min = new PriorityQueue<>();    //小顶堆
    Queue<Integer> max = new PriorityQueue<>((x,y)->(y-x));    //大顶堆
    public void Insert(Integer num) {
        if(min.size() != max.size())
        {
            min.add(num);
            max.add(min.poll());
        }else{
            max.add(num);
            min.add(max.poll());
        }
    }

    public Double GetMedian() {
        if(min.size() != max.size())
        {
            return min.peek()/1.0;
        }else{
            return (min.peek() + max.peek())/2.0;
        }
    }


}

JZ64

  • 滑动窗口的最大值

暴力方法,使用双指针

import java.util.ArrayList;

public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        ArrayList<Integer> ret = new ArrayList<>();
        if(num.length < size || size <= 0)
            return ret;
        int left = 0, right = size - 1;
        while(right <= num.length - 1)
        {
            int max = Integer.MIN_VALUE;
            for(int i = left ; i <= right; i++)
            {
                if(max < num[i])
                    max = num[i];
            }
            ret.add(max);
            left++;
            right++;
        }
        return ret;
    }
}

使用双端队列维护一个非递减数组,来保存窗口内的最大值,以降低复杂度

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;

public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        ArrayList<Integer> ret = new ArrayList<>();
        if(num == null || num.length == 0 || size <= 0 || size > num.length)
            return ret;
        Deque<Integer> deque = new LinkedList<>();
        for(int i = 0; i < size; i++) // 未形成窗口
        {
            while(!deque.isEmpty() && deque.getLast() < num[i])
               deque.removeLast();
            deque.addLast(num[i]);
        }
        ret.add(deque.getFirst());
        for(int i = size; i < num.length; i++) //形成窗口
        {
            if(deque.peekFirst() == num[i-size])
                deque.removeFirst();
            while(!deque.isEmpty() && deque.getLast() < num[i])
                deque.removeLast();
            deque.addLast(num[i]);
            ret.add(deque.getFirst());
        }
        return ret;
    }
}

使用大顶堆

import java.util.ArrayList;
import java.util.PriorityQueue;
public class Solution {
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        ArrayList<Integer> ret = new ArrayList<>();
        if(num == null || num.length == 0 || size <= 0|| size > num.length)
            return ret;
        //大顶堆
        PriorityQueue<Integer> queue = new PriorityQueue<>((o1,o2)->(o2-o1));
        for(int i = 0; i < size; i++)
        {
            queue.add(num[i]);
        }
        ret.add(queue.peek());
        for(int i = size; i < num.length ; i++)
        {
            queue.remove(num[i-size]);
            queue.add(num[i]);
            ret.add(queue.peek());
        }
        return ret;
    }
}

JZ65

  • 矩阵中的路径

使用回溯法进行求解

回溯法模板:

dfs()
{
//1, 检查下标是否满足条件
//2,检查是够被访问过
//3,检查是否满足返回结果条件
//4,都没有返回,说明应该进行下一步递归
dfs(下一次)
//回溯
}
main()
{
for(所有可能的情况)
{
  dfs递归;
}
}
public class Solution {
    public boolean hasPath(char[] matrix, int rows, int cols, char[] str)
    {
        if(rows == 0 || cols == 0)
            return false;
        char[][] board = new char[rows][cols];
        for(int i = 0 ,index = 0; i < rows; i++)
            for(int j = 0; j < cols; j++)
            {
                board[i][j] = matrix[index++];
            }
        for(int i = 0; i < rows; i++)
            for(int j = 0; j < cols; j++)
            {
                if(dfs(board , str, i ,j , 0))
                    return true;
            }
        return false;
    }
    boolean dfs(char[][] board , char[] str , int i , int j , int k)
    {
        if(i >= board.length || i < 0 || j >= board[0].length || j < 0
          || board[i][j] != str[k])
            return false;
        if(k == str.length -1)
            return true;
        board[i][j] = '\0';
        boolean res = dfs(board, str , i+1, j , k+1) || dfs(board , str, i-1, j , k+1)
                        || dfs(board , str , i ,j+1, k+1) || dfs(board , str , i , j - 1 ,k+1);
        //回溯
        board[i][j] = str[k];
        return res;
    }
}

JZ66

  • 机器人的运动范围

搜索问题可以使用深度优先搜索和广度优先搜索(DFS , BFS),定义一个数组保存访问过的状态;

对于矩阵搜索,一般使用深度优先搜索算法;

递归函数的写法:

  1. 终止条件;
  2. 记录状态;
  3. 解决子问题;

DFS回溯算法

public class Solution {
    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];
        
    }
}

更简洁写法:

public class Solution {
    int rows ,cols, threshold;
    boolean[][] visited;
    public int movingCount(int threshold, int rows, int cols)
    {
        this.threshold = threshold;
        this.rows = rows;
        this.cols = cols;
        this.visited = new boolean[rows][cols];
        return dfs(0,0,0,0);
    }
    public int dfs(int i , int j , int si ,int sj){
        if(i >= rows || j >= cols || threshold < si + sj || visited[i][j])
            return 0;
        visited[i][j] = true;
        return 1 + dfs(i+1, j , (i+1)%10 != 0 ? si + 1 : si -8 , sj) + 
            dfs(i , j+1, si , (j+1)%10 != 0 ? sj + 1 : sj - 8);
    }
}
public class Solution {
    
    private boolean[][] visited;
    private int rows;
    private int cols;
    private int threshold;
    public int movingCount(int threshold, int rows, int cols)
    {
        visited = new boolean[rows][cols];
        this.rows = rows;
        this.cols = cols;
        this.threshold = threshold;
        return dfs(threshold,0,0);
    }
    
    private int dfs(int threshold , int i ,int j)
    {
        //递归终止条件
        if(i >= rows || j >= cols || visited[i][j] 
           || bitSum(i) + bitSum(j) > threshold)
            return 0;
        visited[i][j] = true;
        return 1 + dfs(threshold , i + 1, j) + dfs(threshold , i, j + 1);
    }
    
    private int bitSum(int n)    //计算数位和
    {
        int sum = 0;
        while(n > 0)
        {
            sum += n % 10;
            n /= 10;
        }
        return sum;
    }
}

上下左右4个方向都进行搜索:

public class Solution {
    private int threshold;
    private int rows ,cols;
    private boolean[][] visited;
    public int movingCount(int threshold, int rows, int cols)
    {
        this.threshold = threshold;
        this.rows = rows;
        this.cols = cols;
        visited = new boolean[rows][cols];
        return dfs(0,0);
    }
    
    private int dfs(int i ,int j)
    {
        if(i <0 || j < 0 || i >= rows || j >= cols || visited[i][j] || bitSum(i) + bitSum(j) > threshold)
            return 0;
        visited[i][j] = true;
        return 1 + dfs(i+1, j) + dfs(i ,j+1) + dfs(i-1, j) + dfs(i,j-1);
    }
    private int bitSum(int n)
    {
        int sum = 0;
        while(n > 0)
        {
            sum += n % 10;
            n /= 10;
        }
        return sum;
    }
}

广度优先遍历(BFS)实现:

import java.util.Queue;
import java.util.LinkedList;
public class Solution {
    public int movingCount(int threshold, int rows, int cols)
    {
        //BFS
        Queue<int[]> queue = new LinkedList<>();
        boolean[][] visited = new boolean[rows][cols];
        int cnt = 0;
        queue.add(new int[]{0,0});
        while(!queue.isEmpty())
        {
            int[] tmp = queue.poll();
            if(tmp[0] >= rows || tmp[1] >= cols || visited[tmp[0]][tmp[1]]||bitSum(tmp[0]) + bitSum(tmp[1]) > threshold)
                continue;
            visited[tmp[0]][tmp[1]] = true;    //注意标记位置
            cnt++;
            int[] next1 = new int[]{tmp[0] + 1, tmp[1]};
            int[] next2 = new int[]{tmp[0] , tmp[1] + 1};
            
            queue.add(next1);
            queue.add(next2);
        }
        return cnt;
    }
    
    private int bitSum(int n)
    {
        int sum = 0;
        while(n > 0)
        {
            sum += n % 10;
            n /= 10;
        }
        return sum;
    } 
}

JZ67

  • 剪绳子

考察贪心算法

public class Solution {
    public int cutRope(int target) {
        if(target < 2)
            return 0;
        if(target == 2)
            return 1;
        if(target == 3)
            return 2;
        int timesOf3 = target /3;
        if(target - timesOf3 * 3 == 1)
            timesOf3--;
        int timesOf2 = (target - timesOf3 * 3) /2;
        return (int)(Math.pow(3,timesOf3)) * (int)(Math.pow(2, timesOf2));
    }
}

动态规划

public class Solution {
    public int cutRope(int target) {
        int[] dp = new int[target + 1];
        dp[1] = 1;
        for(int i = 2; i <= target; 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[target];
    }
}

你可能感兴趣的:(数据结构,数据结构)