剑指Offer刷题记录 Java

剑指Offer

栈与队列

剑指 Offer 09. 用两个栈实现队列 - 力扣(LeetCode)

class CQueue {
    Stack<Integer> inQueue;
    Stack<Integer> outQueue;
    public CQueue() {
        inQueue = new Stack<>();
        outQueue = new Stack<>();
    }
    
    public void appendTail(int value) {
        inQueue.push(value);
    }
    
    public int deleteHead() {
        if(outQueue.isEmpty()) {
            while (!inQueue.isEmpty()) {
                outQueue.push(inQueue.pop());
            }
        }
        if (outQueue.isEmpty()) return -1;

        return outQueue.pop();
    }
}

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue obj = new CQueue();
 * obj.appendTail(value);
 * int param_2 = obj.deleteHead();
 */

剑指 Offer 30. 包含min函数的栈 - 力扣(LeetCode)

class MinStack {
    Stack<Node> stack;
    /** initialize your data structure here. */
    public MinStack() {
        stack = new Stack<>();
    }
    
    public void push(int x) {
        int min;
        if (stack.isEmpty()) {
            min = x;
        } else {
            min = Math.min(stack.peek().min, x);
        }
        stack.push(new Node(x, min));
    }
    
    public void pop() {
        stack.pop();
    }
    
    public int top() {
        return stack.peek().value;
    }
    
    public int min() {
        return stack.peek().min;
    }
}

class Node {
    int value;
    int min;
    public Node(int value, int min){
        this.value = value;
        this.min = min;
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.min();
 */

剑指 Offer 59 - I. 滑动窗口的最大值 - 力扣(LeetCode)

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        LinkedList<Integer> q = new LinkedList<>();
        int[] res = new int[nums.length - k + 1];
        for(int i = 0; i < nums.length; i++) {
            if (!q.isEmpty() && q.peek() <= i - k) q.poll();
            while (!q.isEmpty() && nums[q.peekLast()] < nums[i]) q.pollLast();
            q.offer(i);
            if (i >= k - 1) res[i - k + 1] = nums[q.peek()];
        }

        return res;

    }
}

★ ★剑指 Offer 59 - II. 队列的最大值 - 力扣(LeetCode)

class MaxQueue {
    LinkedList<Integer> q;
    LinkedList<Integer> max;
    public MaxQueue() {
        q = new LinkedList<>();
        max = new LinkedList<>();
    }
    
    public int max_value() {
        if (q.isEmpty()) return -1;
        return max.peek();
    }
    
    public void push_back(int value) {
        q.offer(value);
        while(!max.isEmpty() && value > max.peekLast()) max.pollLast();//这里的思想很重要
        max.offer(value);
    }
    
    public int pop_front() {
        if (q.isEmpty()) return -1;
        if (q.peek().equals(max.peek())) max.poll();//这里如果用 == 那就错了

        return q.poll();
    }
}

链表

剑指 Offer 06. 从尾到头打印链表 - 力扣(LeetCode)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] reversePrint(ListNode head) {
        
        List<Integer> list = new ArrayList<>();

        while (head != null) {
            list.add(head.val);
            head = head.next;
        }

        int[] res = new int[list.size()];

        for (int i = 0, j = list.size() - 1; i < res.length; i++) {
            res[i] = list.get(j);
            j--;
        }

        return res;
    }
}

剑指 Offer 24. 反转链表 - 力扣(LeetCode)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if (head == null) return head;
        ListNode pre = null;
        ListNode cur = head;
        ListNode temp = new ListNode(0);
        while (temp != null) {
            temp = cur.next;
            cur.next = pre;
            pre = cur;
            if (temp != null) cur = temp;
        }

        return cur;
    }
}

★★剑指 Offer 35. 复杂链表的复制 - 力扣(LeetCode)

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/

// 思路是先复制出所有节点,然后根据节点直接的关系搭桥
class Solution {
    public Node copyRandomList(Node head) {
        
        Map<Node, Node> map = new HashMap<>();
        
        Node cur = head;

        while (cur != null) {
            map.put(cur, new Node(cur.val));
            cur = cur.next;
        }

        cur = head;
        while (cur != null) {
            map.get(cur).next = map.get(cur.next);
            map.get(cur).random = map.get(cur.random);
            cur = cur.next;
        }

        return map.get(head);
    }
}

字符串

剑指 Offer 05. 替换空格 - 力扣(LeetCode)

class Solution {
    public String replaceSpace(String s) {
        StringBuffer res = new StringBuffer();
        for (char c : s.toCharArray()) {
            if (c == ' ') {
                res.append("%20");
            } else {
                res.append(c);
            }
        }

        return new String(res);
    }
}

剑指 Offer 58 - II. 左旋转字符串 - 力扣(LeetCode)

class Solution {
    public String reverseLeftWords(String s, int n) {
        return s.substring(n, s.length()) + s.substring(0, n);
    }
}

★ ★剑指 Offer 67. 把字符串转换成整数 - 力扣(LeetCode)

class Solution {
    public int strToInt(String str) {
        int res = 0, flag = Integer.MAX_VALUE / 10, len = str.length(), sign = 1;
        if (len == 0) return 0;
        int i = 0;
        // 去空格
        while(i < len && str.charAt(i) == ' ')i++;
        if (i >= len) return 0;
        // 确定符号
        if (str.charAt(i) == '-') sign = -1;
        if (str.charAt(i) == '-' || str.charAt(i) == '+') i++;
        if (i >= len) return 0;

        for (int j = i; j < len; j++) {
            if (str.charAt(j) < '0' || str.charAt(j) > '9') break;

            //判断溢出,最为精妙
            if (res > flag || (res == flag && str.charAt(j) > '7')) {
                return sign == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            }

            res = 10 * res + str.charAt(j) - '0';
        } 

        return res * sign;
    }
}

★ ★ ★剑指 Offer 20. 表示数值的字符串 - 力扣(LeetCode)

class Solution {
    public boolean isNumber(String s) {
        char[] c = s.trim().toCharArray();
        boolean isNum = false, isDot = false, isE = false;
        // return false;
        for (int i = 0; i < c.length; i++) {
            if (c[i] >= '0' && c[i] <= '9') isNum = true;
            else if (c[i] == '+' || c[i] == '-') {
                if (!(i == 0) && c[i - 1] != 'E' && c[i - 1] != 'e') return false;
            } else if (c[i] == '.') {
                if (isDot || isE) return false;
                isDot = true;
            } else if (c[i] == 'e' || c[i] == 'E') {
                if (!isNum || isE) return false;
                isE = true;
                isNum =  false;
            } else return false;
        }
        return isNum;
    }
}

查找算法

剑指 Offer 03. 数组中重复的数字 - 力扣(LeetCode)哈希表

class Solution {
    public int findRepeatNumber(int[] nums) {
        Set<Integer> set = new HashSet<>();
        
        for (int i : nums) {
            if (set.contains(i)) {
                return i;
            }
            set.add(i);
        }

        return 1;
    }
}


// 大神算法
class Solution {
    public int findRepeatNumber(int[] nums) {
        int i = 0;
        while(i < nums.length) {
            if(nums[i] == i) {
                i++;
                continue;
            }
            if(nums[nums[i]] == nums[i]) return nums[i];
            int tmp = nums[i];
            nums[i] = nums[tmp];
            nums[tmp] = tmp;
        }
        return -1;
    }
}

剑指 Offer 53 - I. 在排序数组中查找数字 I - 力扣(LeetCode)二分查找

class Solution {
    public int search(int[] nums, int target) {
        if (nums.length == 0) return 0;

        int l = 0, r = nums.length - 1;
        while (l <= r) {
            int mid = l + (r - l) / 2;
            if (nums[mid] == target) {
                int i = mid, j = mid;
                while (i >= 0 && nums[i] == target) i--;
                while (j <= nums.length - 1 && nums[j] == target) j++;
                return j - i - 1;
            }
            else if (nums[mid] < target) l = mid + 1;
            else if (nums[mid] > target) r = mid - 1;
        }

        return 0;
    }
}

剑指 Offer 53 - II. 0~n-1中缺失的数字 - 力扣(LeetCode)二分

class Solution {
    public int missingNumber(int[] nums) {
        int l = 0, r = nums.length - 1;
        while (l <= r) {
            int mid = l + (r - l) / 2;

            if (nums[mid] == mid) l = mid + 1;
            else  r = mid - 1;
            
        }

        return l;
    }
}

剑指 Offer 04. 二维数组中的查找 - 力扣(LeetCode)

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        if (matrix.length == 0) return false;
        int n = matrix.length, m =  matrix[0].length;

        if (n == 0 || m == 0) return false;
        for (int i = 0; i < n; i++) {
            int l = 0, r = m - 1;
            if (matrix[i][l] > target || matrix[i][r] < target) continue;

            while (l <= r) {
                int mid = (l + r) / 2;
                if (matrix[i][mid] > target) {
                    r = mid - 1;
                } else if (matrix[i][mid] < target) {
                    l = mid + 1;
                } else if (matrix[i][mid] == target) {
                    return true;
                }
            }
        }

        return false;
    }
}

剑指 Offer 11. 旋转数组的最小数字 - 力扣(LeetCode)二分查找变式

class Solution {
    public int minArray(int[] numbers) {
        if (numbers.length == 1) return numbers[0];

        int i = 0, j = numbers.length - 1;
        while (i <= j) {
            int mid = (i + j) / 2;
            if (numbers[mid] > numbers[j]) i = mid + 1;
            else if (numbers[mid] < numbers[j]) j = mid;
            else j--;
        }

        return numbers[i];
    }
}

剑指 Offer 50. 第一个只出现一次的字符 - 力扣(LeetCode)哈希表查找

class Solution {
    public char firstUniqChar(String s) {
        char res = ' ';
        int resIndex = 50001;
        int[] letters = new int[26], locations = new int[26];

        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            letters[c - 'a']++;
            if (letters[c - 'a'] == 1){
                locations[c - 'a'] = i;
            }
        }
        
        for (int i = 0; i < 26; i++) {
            if (letters[i] == 1) {
                resIndex = Math.min(resIndex, locations[i]);
            }
        }

        res = resIndex == 50001? ' ' : s.charAt(resIndex);
        return res;
    }
}

搜索与回溯算法

剑指 Offer 32 - I. 从上到下打印二叉树 - 力扣(LeetCode)层序遍历

class Solution {
    Deque<TreeNode> dq;
    List<Integer> res;
    int[] resArr;
    public int[] levelOrder(TreeNode root) {
        dq = new ArrayDeque<>();
        res = new LinkedList<>();
        
        if (root == null) return new int[]{};
        dq.offer(root);
        while(!dq.isEmpty()) {
            int len = dq.size();

            while (len > 0) {
                TreeNode node = dq.poll();
                res.add(node.val);
                if (node.left != null) dq.offer(node.left);
                if (node.right != null) dq.offer(node.right);
                len--;
            }
        }
        resArr = new int[res.size()];
        int x = 0;
        for (Integer i : res) {
            resArr[x++] = i;
        }
        return resArr;
    }
    
}

剑指 Offer 32 - II. 从上到下打印二叉树 II - 力扣(LeetCode)层序遍历

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        
        List<List<Integer>> res = new ArrayList<>();
        Queue<TreeNode> dq = new ArrayDeque<>();
        
        if (root == null) return res;
        dq.offer(root);
        
        while(!dq.isEmpty()) {
            int len = dq.size();
            List<Integer> temp = new ArrayList<>();

            while (len > 0) {
                TreeNode node = dq.poll();
                temp.add(node.val);
                if (node.left != null) dq.offer(node.left);
                if (node.right != null) dq.offer(node.right);
                len--;
            }

            res.add(temp);
        }
        
        return res;
        
    }
}

剑指 Offer 32 - III. 从上到下打印二叉树 III - 力扣(LeetCode)层序遍历变式

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        ArrayDeque<TreeNode> dq = new ArrayDeque<>();
        if (root == null) return res;

        dq.offer(root);
        boolean leftFlag = true;

        while (!dq.isEmpty()) {
            int len = dq.size();
            ArrayDeque<TreeNode> nextDq = dq.clone();
            List<Integer> temp = new ArrayList<>();
            while(len > 0) {
                TreeNode node;
                if (leftFlag) node = dq.poll();
                else node = dq.pollLast();
                temp.add(node.val);
                TreeNode node2 = nextDq.poll();
                if (node2.left != null) nextDq.offer(node2.left);
                if (node2.right != null) nextDq.offer(node2.right);
                len--;
            }
            res.add(temp);
            dq = nextDq;
            leftFlag = !leftFlag;
        }
        return res;
    }
}

★ ★ ★剑指 Offer 26. 树的子结构 - 力扣(LeetCode)双递归(主函数和辅助函数) + 二叉树

回溯三部曲

  1. 终止条件
  2. 返回值
  3. 单层循环逻辑
class Solution {
    public boolean isSubStructure(TreeNode A, TreeNode B) {
        if (A == null || B == null) return false;

        return dfs(A, B) || isSubStructure(A.left, B) || isSubStructure(A.right, B);
    }
    // 同公共节点的判断
    public boolean dfs(TreeNode a, TreeNode b) {
        if (b == null) return true;
        if (a == null) return false;

        return a.val == b.val && dfs(a.left, b.left) && dfs(a.right, b.right);
    }
    
}

★ ★ ★剑指 Offer 27. 二叉树的镜像 - 力扣(LeetCode)递归 + 二叉树

class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if (root == null) return root;
        TreeNode temp = root.left;
        root.left = mirrorTree(root.right);
        root.right = mirrorTree(temp);

        return root;
    }

    
}

剑指 Offer 28. 对称的二叉树 - 力扣(LeetCode)递归+二叉树

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;

        return dfs(root.left, root.right);
    }

    public boolean dfs(TreeNode a, TreeNode b) {
        if (a == null && b == null) return true;
        else if (a == null || b == null) return false;

        return a.val == b.val && dfs(a.left, b.right) && dfs(a.right, b.left);
    }
}

中等

★ ★ ★剑指 Offer 12. 矩阵中的路径 - 力扣(LeetCode)

第二次主要是

class Solution {
    boolean[][] used;
    public boolean exist(char[][] board, String word) {
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                used = new boolean[board.length][board[0].length];// 每次搜索都重置地图使用标记
                if (dfs(board, i, j, word, 0)) return true;
            }
        }
        return false;
    }
    public boolean dfs(char[][]board, int x, int y, String s, int index) {
        if (index == s.length()) return true;
        if (x < 0 || x >= board.length || y < 0 || y >= board[0].length) return false;
        char c = s.charAt(index);
        if (board[x][y] != c || used[x][y]) return false;
        
        used[x][y] = true;
        boolean res = dfs(board, x - 1, y, s, index + 1) || dfs(board, x + 1, y, s, index + 1) 
            || dfs(board, x, y - 1, s, index + 1) || dfs(board, x, y + 1, s, index + 1); // 这一步也非常巧妙
        used[x][y] = false;//第三次忘记回溯

        return res;
    }
}

剑指 Offer 13. 机器人的运动范围 - 力扣(LeetCode)纯搜索

class Solution {
    boolean[][] used;
    int res;
    public int movingCount(int m, int n, int k) {
        used = new boolean[m][n];
        dfs(0,0,m,n,k);
        
        return res;
    }
    
    public void dfs(int x, int y, int m, int n, int k) {
        if (sum(x) + sum(y) > k || x < 0 || x >= m || y < 0 || y >= n || used[x][y]) return;
        else if (sum(x) + sum(y) <= k && !used[x][y]) {
             res++;
             used[x][y] = true;
        }
        dfs(x + 1, y, m, n, k);
        dfs(x - 1, y, m, n, k);
        dfs(x, y + 1, m, n, k);
        dfs(x, y - 1, m, n, k);
    }


    public int sum(int n) {
        int res = 0;
        while (n > 0) {
            res += n % 10;
            n /= 10;
        }
        return res;
    }
}

剑指 Offer 34. 二叉树中和为某一值的路径 - 力扣(LeetCode)回溯

class Solution {
    List<List<Integer>> res;
    LinkedList<Integer> temp;
    int sum = 0;
    public List<List<Integer>> pathSum(TreeNode root, int target) {
        res = new ArrayList<>();
        temp = new LinkedList<>();
        dfs(root, target);
        return res;
    }

    public void dfs(TreeNode root, int target) {
        if(root == null) return;
        
        temp.add(root.val);
        sum += root.val;
        if(sum == target && root.right == null && root.left == null) {
            res.add(new ArrayList<>(temp));
        }
        dfs(root.left, target);
        dfs(root.right, target);
        sum -= root.val;
        temp.removeLast();
    }
}

★ ★剑指 Offer 36. 二叉搜索树与双向链表 - 力扣(LeetCode)

class Solution {
    Node pre, first;
    public Node treeToDoublyList(Node root) {
        if (root == null) return root;
        dfs(root);
        first.left = pre;
        pre.right = first;
        return first;
    }

    public void dfs(Node root) {
        if (root == null) return;

        dfs(root.left);
        if (pre == null) {
            first = root;
        }
        else {
            pre.right = root;
            root.left = pre;
        }
        pre = root;
        
        dfs(root.right);
 
    }
}

剑指 Offer 54. 二叉搜索树的第k大节点 - 力扣(LeetCode)回溯

class Solution {
    int index, res;
    public int kthLargest(TreeNode root, int k) {
        dfs(root, k);
        return res;
    }

    public void dfs(TreeNode root, int k) {
        if (root == null) return;

        dfs(root.right, k);
        index++;
        if (index == k) res = root.val;
        dfs(root.left, k);

    } 
}

剑指 Offer 55 - I. 二叉树的深度 - 力扣(LeetCode)搜索

class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) return 0;

        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }
}

★ ★剑指 Offer 55 - II. 平衡二叉树 - 力扣(LeetCode)

class Solution {
    public boolean isBalanced(TreeNode root) {
        return dfs(root) != -1;
    }

    public int dfs(TreeNode root) {
        if (root == null) return 0;
        int right = dfs(root.left), left = dfs(root.right);

        if (right == -1) return -1;
        if (left == -1) return -1;
        if (Math.abs(right - left) > 1) return -1;

        return Math.max(right, left) + 1;
    }
}

★ ★ ★剑指 Offer 64. 求1+2+…+n - 力扣(LeetCode)不能用判断语句

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

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == p) return p;
        if (root == q) return q;
        if (root == null) return null;

        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);

        if (left != null && right != null) return root;
        if (left == null && right != null) return right;
        
        return left;

    }
}

//第二次不同的想法
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (p.val > q.val) {
            TreeNode tmp = q;
            q = p;
            p = tmp;
        }
        if(root.val < q.val && root.val > p.val) return root;
        else if (root.val == p.val) return p;
        else if (root.val == q.val) return q;

        if (root.val > q.val) return lowestCommonAncestor(root.left, p, q);
        return lowestCommonAncestor(root.right, p, q); 
    }
}

★ ★剑指 Offer 68 - II. 二叉树的最近公共祖先 - 力扣(LeetCode)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == p) return p;
        if (root == q) return q;
        if (root == null) return null;

        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);

        if (left != null && right != null) return root;
        if (left == null && right != null) return right;
        
        return left;
    }
}

★ ★ ★ ★ ★剑指 Offer 37. 序列化二叉树 题解 - 力扣(LeetCode)

public class Codec {
    String s;
    TreeNode root;

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if (root == null) return "null,";

        s = root.val + ",";
        s += serialize(root.left);
        s += serialize(root.right);

        return s;
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        Queue<String> q = new LinkedList<>();
        String[] arr = data.split(",");
        for (String i : arr) {
            q.offer(i);
        }

        return dfs(q);
    }

    public TreeNode dfs(Queue<String> q){
        String val = q.poll();
        if (val.equals("null")) {
            return null;
        }
        TreeNode root = new TreeNode(Integer.valueOf(val));
        root.left = dfs(q);
        root.right = dfs(q);

        return root;
    }
}

// 第二次
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if (root == null) return "[]";
        StringBuffer res = new StringBuffer();
        res.append("[");
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        while(!q.isEmpty()) {
            TreeNode n = q.poll();
            if (n != null) {
                res.append(n.val + ",");
                q.offer(n.left);
                q.offer(n.right);
            }
            else res.append("null,");
        }

        res.deleteCharAt(res.length() - 1);
        res.append(']');

        return res.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if (data.equals("[]")) return null;
        String[] values = data.substring(1, data.length() - 1).split(",");
        Queue<TreeNode> q = new LinkedList<>();
        TreeNode res = new TreeNode(Integer.parseInt(values[0]));
        q.offer(res);
        int i = 1;
        while(!q.isEmpty()) {
            TreeNode node = q.poll();
            if (!values[i].equals("null")) {
                node.left = new TreeNode(Integer.parseInt(values[i]));
                q.offer(node.left);
            }
            i++;
            if (!values[i].equals("null")) {
                node.right = new TreeNode(Integer.parseInt(values[i]));
                q.offer(node.right);
            }
            i++;
        }
        return res;
    }
}

剑指 Offer 38. 字符串的排列 - 力扣(LeetCode)

class Solution {
    StringBuffer sb;
    List<String> res;
    boolean[] used;
    public String[] permutation(String s) {
        sb = new StringBuffer();
        res = new ArrayList<>();
        used = new boolean[s.length()];
        char[] c = s.toCharArray();
        Arrays.sort(c);
        dfs(c, c.length);
        String[] arr = new String[res.size()];
        int i = 0;
        for (String str : res) {
            arr[i++] = str;
        }
        return arr;
    }

    public void dfs(char[] c, int end) {
        if (sb.length() == end) {
            res.add(sb.toString());
            
        }
        for (int i = 0; i < end; i++) {
            if (i > 0 && c[i] == c[i - 1] && !used[i - 1]) continue;
            if (used[i]) continue;
            sb.append(c[i]);
            used[i] = true;
            dfs(c, end);
            used[i] = false;
            sb.deleteCharAt(sb.length() - 1);
        }
    }
}

动态规划

剑指 Offer 10- I. 斐波那契数列 - 力扣(LeetCode)阶梯问题

class Solution {
    public int fib(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;
        int mod = 1000000007;
        
        int[] dp = new int[n + 1];
        dp[1] = 1;
        for (int i = 2; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
            dp[i] %= mod;
        }

        return dp[n];
    }
}

剑指 Offer 10- II. 青蛙跳台阶问题 - 力扣(LeetCode)阶梯问题

class Solution {
    public int numWays(int n) {
        if (n == 0) return 1;

        int mod = 1000000007;
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[0] = 1;
        for (int i = 2; i <= n; i++) {
            dp[i] = dp[i - 2] + dp[i - 1];
            dp[i] %= mod;
        }

        return dp[n];
    }
}

剑指 Offer 63. 股票的最大利润 - 力扣(LeetCode)

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        if (n == 0) return 0;
        int res = 0;
        // dp[i] 代表第i天的最大利润
        int dp[] = new int[n + 1];
        // 代表前面的最低价格
        int buy = -prices[0];
        for (int i = 2; i <= n; i++) {
            dp[i] = Math.max(dp[i], buy + prices[i - 1]);
            buy = Math.max(buy, -prices[i - 1]);
            res = Math.max(res, dp[i]);
        }

        return res;
    }
}

剑指 Offer 42. 连续子数组的最大和 - 力扣(LeetCode)最大和问题,大神好解

class Solution {
    public int maxSubArray(int[] nums) {
        if (nums.length == 1) return nums[0];
        //dp[i] 表示包含第i - 1个元素的连续子数组最大和
        int[] dp = new int[nums.length + 1];
        int res = nums[0];
        for (int i = 1; i <= nums.length; i++) {
            dp[i] = Math.max(nums[i - 1], dp[i - 1] + nums[i - 1]);
            res = Math.max(res, dp[i]);
        }

        return res;
    }
}
// 直接在数组修改,不用额外空间
class Solution {
    public int maxSubArray(int[] nums) {
        int res = nums[0];
        for(int i = 1; i < nums.length; i++) {
            nums[i] += Math.max(nums[i - 1], 0);
            res = Math.max(res, nums[i]);
        }
        return res;
    }
}

剑指 Offer 47. 礼物的最大价值 - 力扣(LeetCode)最大和,直接修改数组

class Solution {
    public int maxValue(int[][] grid) {
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) {
                if (i == 0 & j == 0) continue;
                else if (i == 0) grid[i][j] += grid[i][j - 1];
                else if (j == 0) grid[i][j] += grid[i - 1][j];
                else grid[i][j] += Math.max(grid[i - 1][j], grid[i][j - 1]);
            }
        }

        return grid[grid.length - 1][grid[0].length - 1];
    }
}

剑指 Offer 46. 把数字翻译成字符串 - 力扣(LeetCode)阶梯问题

class Solution {
    public int translateNum(int num) {
        if (num < 10) return 1;
        char[] c = String.valueOf(num).toCharArray();

        int dp[] = new int[c.length + 1];
        dp[0] = 1;
        dp[1] = 1;
        for (int i = 2; i <= c.length; i++) {
            if (c[i - 2] != '0' && (c[i - 2] - '0') * 10 + (c[i - 1] - '0') < 26) {
                dp[i] = dp[i - 1] + dp[i - 2]; //满足条件则可以将前一步阶梯加上前两步阶梯的可能
            } else {
                dp[i] = dp[i - 1];
            }
        }

        return dp[c.length];
    }
}

剑指 Offer 48. 最长不含重复字符的子字符串 - 力扣(LeetCode)动态规划 + 哈希表

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if (s.length() == 0) return 0;
        int[] loc = new int[128];
        Arrays.fill(loc, -1);
        int start = 0;
        int res = 0;
        for (int i = 0; i < s.length(); i++) {
            int c = s.charAt(i) - ' ';
            if (loc[c] != -1) {
                start = Math.max(start, loc[c] + 1);
            }

            res = Math.max(res, i - start + 1);
            loc[c] = i;
        }

        return res;
    }
}

★ ★ ★剑指 Offer 19. 正则表达式匹配 - 力扣(LeetCode)

第二次死在出现0次的地方

class Solution {
    public boolean isMatch(String s, String p) {
        boolean[][] dp = new boolean[s.length() + 1][p.length() + 1];
        dp[0][0] = true;
        for (int j = 1; j <= p.length(); j++) {
            if (p.charAt(j - 1) == '*' && dp[0][j - 2]) dp[0][j] = true;
        }
        for (int i = 1; i <= s.length(); i++) {
            for (int j = 1; j <= p.length(); j++) {
                if (p.charAt(j - 1) == '.' || p.charAt(j - 1) == s.charAt(i - 1)) dp[i][j] = dp[i - 1][j - 1];
                else if (p.charAt(j - 1) == '*') {
                    if (p.charAt(j - 2) == s.charAt(i - 1) || p.charAt(j - 2) == '.') {
                        dp[i][j] = dp[i - 1][j]// 出现1次以上
                        || dp[i][j - 2]; // 出现0次(第二次死在这)
                    }
                    else dp[i][j] = dp[i][j - 2];// 若无用到* 的功能,只能将他变0
                }
            }
        }

        return dp[s.length()][p.length()];
    }
}

★ ★剑指 Offer 49. 丑数 - 力扣(LeetCode)

class Solution {
    public int nthUglyNumber(int n) {
        int p2 = 1, p3 = 1, p5 = 1;
        
        int[] dp = new int[n + 1];
        dp[1] = 1;
        for (int i = 2; i <= n; i++) {
            int num2 = dp[p2] * 2, num3 = dp[p3] * 3, num5 = dp[p5] * 5;
            dp[i] = Math.min(Math.min(num2, num3), num5);

            if (num2 == dp[i]) p2++;//这里用else if不行
            if (num3 == dp[i]) p3++;
            if (num5 == dp[i]) p5++;
        }
        
        return dp[n];
    }
}

★ ★剑指 Offer 60. n个骰子的点数 - 力扣(LeetCode)

 class Solution {
    public double[] dicesProbability(int n) {
        double[] dp = new double[6];
        Arrays.fill(dp, 1.0 / 6.0);
        for (int i = 2; i <= n; i++) {
            double[] temp = new double[5 * i + 1];
            for (int j = 0; j < dp.length; j++) {
                for (int k = 0; k < 6; k++) {
                    temp[k + j] += dp[j] / 6.0;
                }
            }
            
            dp = temp;
        }

        return dp;
    }
}

双指针

剑指 Offer 18. 删除链表的节点 - 力扣(LeetCode)双指针+链表

class Solution {
    public ListNode deleteNode(ListNode head, int val) {
        ListNode dimmy = new ListNode(0);
        dimmy.next = head;
        ListNode pre = dimmy, cur = head;

        while (cur.val != val) {
            cur = cur.next;
            pre = pre.next;
        }

        pre.next = cur.next;

        return dimmy.next;
    }
}

剑指 Offer 22. 链表中倒数第k个节点 - 力扣(LeetCode)双指针加链表

class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        ListNode cur = head;
        int len = 0;
        
        while (cur != null) {
            len++;
            cur = cur.next;
        }

        cur = head;

        while(len - k > 0) {
            cur = cur.next;
            len--;
        }

        return cur;
    }
}

剑指 Offer 25. 合并两个排序的链表 - 力扣(LeetCode)双指针+链表

class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1 == null) return l2;
        if(l2 == null) return l1;

        ListNode dimmy = new ListNode(0);
        ListNode pre = dimmy;
        while (l1 != null && l2 != null) {
            if (l1.val < l2.val) {
                dimmy.next = l1;
                l1 = l1.next;
            } else {
                dimmy.next = l2;
                l2 = l2.next;
            }

            dimmy = dimmy.next;
        }

        if (l1 != null) dimmy.next = l1;
        if (l2 != null) dimmy.next = l2;

        return pre.next;
    }
}

剑指 Offer 52. 两个链表的第一个公共节点 - 力扣(LeetCode)

class Solution {
    ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode curA = headA;
        ListNode curB = headB, res = null;
        int lenA = 0, lenB = 0;
        while (curA != null) {
            lenA++;
            curA = curA.next;
        }
        while (curB != null) {
            lenB++;
            curB = curB.next;
        }
        
        if (lenA > lenB) {
            curA = headA;
            curB = headB;
        } else {
            curA = headB;
            curB = headA;
        }

        int len = Math.abs(lenA - lenB);

        while (len > 0) {
            curA = curA.next;
            len--;
        }

        while(curA != null) {
            if (curA == curB) {
                res = curA;
                break;
            }
            curA = curA.next;
            curB = curB.next;
        }

        return res;
    }
}

剑指 Offer 21. 调整数组顺序使奇数位于偶数前面 - 力扣(LeetCode)

class Solution {
    public int[] exchange(int[] nums) {
        if (nums.length == 0) return nums;
        int l = 0, r = nums.length - 1;

        while (l < r) {
            while (l < r && nums[l] % 2 == 1) l++;
            while (l < r && nums[r] % 2 == 0) r--;
            if (l < r) {
                int temp = nums[l];
                nums[l] = nums[r];
                nums[r] = temp;
            }
        }

        return nums;
    }

    
}

剑指 Offer 57. 和为s的两个数字 - 力扣(LeetCode)

// 哈希表
class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res = new int[2];
        Map<Integer,Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(nums[i])) {
                res[0] = nums[i];
                res[1] = map.get(nums[i]);
                break;
            }
            map.put(target - nums[i], nums[i]);
        }

        return res[0] == 0 ? new int[]{} : res;
    }
}

// 双指针
class Solution {
    public int[] twoSum(int[] nums, int target) {
        int l = 0, r = nums.length - 1;
        while (l < r) {
            if (nums[l] + nums[r] < target) l++;
            if (nums[l] + nums[r] > target) r--;
            if (nums[l] + nums[r] == target) return new int[]{nums[l], nums[r]};
        }

        return new int[]{};
    }
}

剑指 Offer 58 - I. 翻转单词顺序 - 力扣(LeetCode)

class Solution {
    public String reverseWords(String s) {
        s = reverse(s.trim());
        if (s.length() == 0) return "";
        StringBuffer res = new StringBuffer();
        int l = 0, r = 0;
        while (r < s.length()) {
            while (s.charAt(l) == ' ') l++;
            r = l;
            while (r < s.length() && s.charAt(r) != ' ') r++;
            res.append(reverse(s.substring(l, r)) + ' ');
            l = r;
        }
        res.deleteCharAt(res.length() - 1);
        return res.toString();
    }

    public String reverse(String s) {
        char[] c = s.toCharArray();
        int l = 0, r = c.length - 1;
        while (l < r) {
            char tmp = c[l];
            c[l] = c[r];
            c[r] = tmp;
            l++;
            r--;
        }
        return new String(c);
    }
}

排序

★ ★剑指 Offer 45. 把数组排成最小的数 - 力扣(LeetCode)

class Solution {
    public String minNumber(int[] nums) {
        String[] s = new String[nums.length];
        for (int i = 0; i < nums.length; i++) {
            s[i] = String.valueOf(nums[i]);
        }

        Arrays.sort(s, (a, b) -> (a + b).compareTo(b + a));
        String res = "";
        for (String o : s) {
            res += o;
        }
        return res;
    }
}

剑指 Offer 61. 扑克牌中的顺子 - 力扣(LeetCode)

class Solution {
    public boolean isStraight(int[] nums) {
        Arrays.sort(nums);
        int zero = 0;
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == 0) {
                zero++;
                continue;
            }
            if (i > 0 && nums[i] - nums[i - 1] == 1 ) continue;
            else if (i > 0 && nums[i - 1] != 0 && nums[i] == nums[i - 1]) return false;
            else if (i > 0 && nums[i - 1] != 0 && nums[i] - nums[i - 1] > 1) {
                zero -= nums[i] - nums[i - 1] - 1;
            }
        }
        return zero >= 0;
    }
}

★ ★剑指 Offer 40. 最小的k个数 - 力扣(LeetCode)快速排序

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if (arr.length == 0) return new int[]{};

        fastSort(0, arr.length - 1, arr);

        return Arrays.copyOfRange(arr, 0, k);
    }

    // 实质上是逐次找到每个数最终的位置,从索引0开始
    public void fastSort(int l, int r, int[] arr) {
        
        if (l >= r) return;//数组长度为1的时候直接结束

        int i = l, j = r;
        while(i < j) {
            while (i < j && arr[l] <= arr[j]) j--;//左边为哨兵,这两步分别找比他小的数,比他大的数
            while (i < j && arr[l] >= arr[i]) i++;
            swap(i, j, arr);//这两个数交换
        }
        swap(i, l, arr);//与哨兵交换,i的位置就是最终的位置
        fastSort(l, i - 1, arr);// 这里要注意左端是l
        fastSort(i + 1, r, arr);// 这里要注意右端是r
    }

    public void swap(int i, int j, int[] arr) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
}

剑指 Offer 41. 数据流中的中位数 - 力扣(LeetCode)优先队列

class MedianFinder {
    PriorityQueue<Integer> dq1;
    PriorityQueue<Integer> dq2;
    /** initialize your data structure here. */
    public MedianFinder() {
        dq1 = new PriorityQueue<>((a, b) -> b - a);
        dq2 = new PriorityQueue<>((a, b) -> a - b);
    }
    
    public void addNum(int num) {
        if (dq1.isEmpty()) {
            dq1.offer(num);
            return;
        }
        if (dq1.peek() > num) {
            dq1.offer(num);
            if (dq1.size() - dq2.size() > 1) dq2.offer(dq1.poll());
        } else if (num >= dq1.peek()) {
            dq2.offer(num);
            if (dq1.size() < dq2.size()) dq1.offer(dq2.poll());
        }
        
    }
    
    public double findMedian() {
        if (dq1.size() == dq2.size()) return ((double) dq1.peek() + dq2.peek()) / 2;
        
        return dq1.peek();
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

分治算法

★ ★剑指 Offer 07. 重建二叉树 - 力扣(LeetCode)

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder.length == 0) return null;//终止条件要清晰

        TreeNode root = new TreeNode(preorder[0]); 
        int i = 0;
        while(i < inorder.length && inorder[i] != preorder[0]) i++;
        
        int len = i;
        root.left = buildTree(Arrays.copyOfRange(preorder, 1, 1 + len), Arrays.copyOfRange(inorder, 0, i));
        root.right = buildTree(Arrays.copyOfRange(preorder, 1 + len, preorder.length), Arrays.copyOfRange(inorder, i + 1, inorder.length));

        return root;
    }
}

★ ★ ★剑指 Offer 16. 数值的整数次方 - 力扣(LeetCode)快速幂

class Solution {
    public double myPow(double x, int n) {
        long N = n;
        double res = 1.0;
        if (N < 0) {
            N = -N;
            x = 1 / x;
        }

        while (N > 0) {
            if ((N & 1) == 1) res *= x;  //如果N是奇数先乘一次,到最后一次循环,N=1 乘上就是res
            x *= x;
            N >>= 1; //右移一位相当于除以2
        }

        return res;
    }
}

剑指 Offer 33. 二叉搜索树的后序遍历序列 - 力扣(LeetCode)

class Solution {
    public boolean verifyPostorder(int[] postorder) {
        return dfs(postorder, 0, postorder.length - 1);
    }
    public boolean dfs(int[] postorder, int i, int j) {
        if (i >= j) return true;
        int p = i;
        
        while (postorder[p] < postorder[j]) p++;
        int l = p;// 左右子树分界点
        while (postorder[p] > postorder[j]) p++;
        

        return p == j && dfs(postorder, i, l - 1) && dfs(postorder, l, j - 1);
        
    }
}

★ ★ ★剑指 Offer 51. 数组中的逆序对 - 力扣(LeetCode)归并排序

class Solution {
    int[] tmp;
    public int reversePairs(int[] nums) {
        tmp = new int[nums.length];
        return sort(nums, 0, nums.length - 1);
    }
    public int sort(int[]nums, int l, int r) {
        
        if (l >= r) return 0;

        int m = l + (r - l) / 2;
        //分治算法
        int res = sort(nums, l, m) + sort(nums, m + 1, r);
        
        int i = l, j = m + 1;
        for (int k = l; k <= r; k++) {
            tmp[k] = nums[k];
        }
        for (int k = l; k <= r; k++) {
            if (i > m) {
                nums[k] = tmp[j++];  
            } else if (j > r || tmp[i] <= tmp[j]) {
                nums[k] = tmp[i++];
            } else {
                nums[k] = tmp[j++];
                res += m - i + 1;// 这一步忘了
                
            }
        }
            
        
        
        return res;
    }
}

位运算

★ ★剑指 Offer 15. 二进制中1的个数 - 力扣(LeetCode)

第二次,1. n != 0判断条件和>>>右移就是连符号一起移,>> 是不移符号

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int res = 0;
        while (n != 0) {// 负数的话进不了循环,所以不能用n > 0;
            if ((n & 1) == 1) res++;
            n >>>= 1;// java中无符号数要>>>进行右移,与>>有区别
        }
        return res;
    }
}

★ ★剑指 Offer 65. 不用加减乘除做加法 - 力扣(LeetCode)

class Solution {
    public int add(int a, int b) {
        while (b != 0) {
            int c = (a & b) << 1; // 进位
            a ^= b;//非进位和
            b = c;//进位还需要进行下一场进位和非进位和,直至为0;
        }

        return a;
    }
}

★ ★剑指 Offer 56 - I. 数组中数字出现的次数 - 力扣(LeetCode)

class Solution {
    public int[] singleNumbers(int[] nums) {
        int x = 0, y = 0, n = 0, m = 1;// n = x ^ y, 辅助m
        for (int i : nums) {
            n ^= i;
        }
        while ((m & n) == 0) m <<= 1;// x和y肯定有一位是是不一样

        for (int i : nums) {
            if ((i & m) == 0) x ^= i;// 或者(i & m) != 0
            else y ^= i;
        }

        return new int[]{x, y};
    }
}

★ ★剑指 Offer 56 - II. 数组中数字出现的次数 II - 力扣(LeetCode)

/**这道题可以使用位运算来解决。我们可以考虑对于每一位,统计所有数字在该位上出现的次数之和,然后对3取余,剩下的就是只现一次的数字在该位上的值。最后将每一位的值拼接起来,就得到了只出现一次的数字。
体来说,我们可以使用两个变量 ones 和 twos 分别记录所有数字在每一位上出现一次和两次的情况。对当前数字 num,更新 ones 和 twos 的方法如下:
ones = ones ^ num & ~twos
twos = twos ^ num & ~ones
第一步中,ones ^= num 表示将 num 加入 ones 中,如果 num 已经在 ones 中出现过,则将其删除。num &twos 表示将 num 从 twos 中删除,因为如果 num 在 twos 中出现过,则说明 num 在该位上出现了两次,而我们只需要记录出现一次的数字。
第二步中,twos ^= num 表示将 num 加入 twos 中, num 已经在 twos 中出现过,则将其删除。num & ~ones 表示将 num 从 ones 中删除,因为如果 num 在 ones 中出现过,则说明 num 在该位上出现了两次,而我们只需要记录出现一次的数字。
最后,只出现一次的数字就是 ones。*/
class Solution {
    public int singleNumber(int[] nums) {
        int ones = 0, two = 0;
        for(int i : nums) {
            ones = ones ^ i & ~two;
            two = two ^ i & ~ones;
        }

        return ones;
    }
}

数学

★ ★剑指 Offer 39. 数组中出现次数超过一半的数字 - 力扣(LeetCode)摩尔投票

class Solution {
    public int majorityElement(int[] nums) {
        int vote = 0;
        int res = 0;
        for (int i = 0; i < nums.length; i++) {
            if (vote == 0) res = nums[i];
            vote += nums[i] == res ? 1 : -1;
            
        }

        return res;
    }
}

★ ★剑指 Offer 66. 构建乘积数组 - 力扣(LeetCode)

class Solution {
    public int[] constructArr(int[] a) {
        int len = a.length;
		
        if (len == 0) return new int[0];
        int[] res = new int[len];
        res[0] = 1;
        int tmp = 1;
        
        //              a1   a2     a3
        // 第一个for     1   a1     a1*a2
        // 第二个for   a2*a3 a1*a3  a1*a2
        
        
        for (int i = 1; i < len; i++) {
            res[i] = res[i - 1] * a[i - 1];
        }
        
        for (int i = len - 2; i >= 0; i--) {
            tmp *= a[i + 1];
            res[i] *= tmp;
        }

        return res;
    }
}

剑指 Offer 14- II. 剪绳子 II - 力扣(LeetCode)

class Solution {
    public int cuttingRope(int n) {
        int mod = 1000000007;
        long res = 1;
        if (n == 2) return 1;
        if (n == 3) return 2;
        if (n == 4) return 4;
        while (n > 4) {
            res *= 3;
            n -= 3;
            res %= mod;
        }
        res *= n;
        res %= mod;
        return (int)res;
    }
}

剑指 Offer 57. 和为s的两个数字 - 力扣(LeetCode)

class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(nums[i])) {
                return new int[]{nums[i], nums[(int)map.get(nums[i])]};
            }
            map.put(target - nums[i], i);
        }

        return new int[]{};
    }
}

★ ★ ★剑指 Offer 62. 圆圈中最后剩下的数字 - 力扣(LeetCode)约瑟夫环

/**

*/
class Solution {
    public int lastRemaining(int n, int m) {
        int x = 0;
        for (int i = 2; i <= n; i++) {
            x = (x + m) % i;
        }
        return x;
    }
}

★ ★ ★剑指 Offer 43. 1~n 整数中 1 出现的次数 - 力扣(LeetCode)位数动态规划

class Solution {
    // 用2304 2314 2324举例分析
    public int countDigitOne(int n) {
        int digit = 1, high = n / 10, low = 0, cur = n % 10, res = 0;
        while (high != 0 || cur != 0) {// 最后是两者都为0则不用运算
            if (cur == 0) res += high * digit;
            if (cur == 1) res += high * digit + low + 1;
            if (cur > 1) res += (high + 1) * digit;
            
            low += cur * digit;
            digit *= 10;
            cur = high % 10;
            high /= 10;
        }

        return res;

    }
}

★ ★ 剑指 Offer 44. 数字序列中某一位的数字 - 力扣(LeetCode)

/* 数字范围    数量  位数    占多少位
    1-9        9      1       9
    10-99      90     2       180
    100-999    900    3       2700
    1000-9999  9000   4       36000  ...

    例如 2901 = 9 + 180 + 2700 + 12 即一定是4位数,第12位   n = 12;
    数据为 = 1000 + (12 - 1)/ 4  = 1000 + 2 = 1002
    定位1002中的位置 = (n - 1) %  4 = 3    s.charAt(3) = 2;
*/

// 第二次感悟,一定要用long型,不然肯定出错

class Solution {
    public int findNthDigit(int n) {
        int digit = 1;   // n所在数字的位数
        long start = 1;  // 数字范围开始的第一个数
        long count = 9;  // 占多少位
        while(n > count){
            n -= count;
            digit++;
            start *= 10;
            count = digit * start * 9;
        }
        long num = start + (n - 1) / digit;
        return Long.toString(num).charAt((n - 1) % digit) - '0';
    }
}

模拟

剑指 Offer 31. 栈的压入、弹出序列 - 力扣(LeetCode)

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

剑指 Offer 29. 顺时针打印矩阵 - 力扣(LeetCode)

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if (matrix.length == 0 || matrix[0].length == 0) return new int[]{};
        int start = 0, m = matrix.length, n = matrix[0].length;
        int loop = Math.min(m, n) / 2;
        int[] res = new int[m * n];
        int index = 0;
        while (loop > 0) {
            int x = start, y = start;
            for (; y < n - 1 - start; y++) {
                res[index++] = matrix[x][y];
            }
            for (; x < m - 1 - start; x++) {
                res[index++] = matrix[x][y];
            }
            for (; y > start; y--) {
                res[index++] = matrix[x][y];
            }
            for(; x > start; x--) {
                res[index++] = matrix[x][y];
            }
            loop--;
            start++;
        }
        if (m > n && n % 2 == 1) {
            int x = start, y = start;
            while (index < res.length) {
                res[index++] = matrix[x++][y];
            }
        }
        if (m < n && m % 2 == 1) {
            int x = start, y = start;
            while (index < res.length) {
                res[index++] = matrix[x][y++];
            }
        }
        if (m == n && n % 2 == 1) {
            res[index] = matrix[start][start];
        }

        return res;

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值