算法刷题整理

一.字符串处理

1. 空格替换 力扣

class Solution {
// 简单方法:replaceAll()
    public String replaceSpace1(String s) {
        if(s == null || s.length() == 0){
            return s;
        }
        return s.replaceAll(" ", "%20");
    }
// 常规方法:StringBuilder
    public String replaceSpace2(String s) {
        if(s == null || s.length() == 0){
            return s;
        }
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i

2.左旋转字符串 力扣

class Solution {
    // 简单方法,额外内存
    public String reverseLeftWords(String s, int n) {
        if(s == null || s.length() <= n){
            return s;
        }
        String s1 = s.substring(0, n);
        String s2 = s.substring(n, s.length());
        return s2+s1;
    }

    // 不使用额外内存方法 按n切开,各自翻转字符串,最后整体翻转一次
    public String reverseLeftWords(String s, int n) {
        if (s == null || s.length() == 0) {
            return s;
        }
        char[] ss = s.toCharArray();
        reserve(ss, 0, n-1);
        reserve(ss, n, ss.length-1);
        reserve(ss, 0, ss.length-1);
        return new String(ss);
    }
    public void reserve(char[] s, int left, int right) {
        while (left <= right) {
            char temp = s[left];
            s[left] = s[right];
            s[right] = temp;
            left++;
            right--;
        }
    }
}

3.表示数值的字符串 力扣

通过有限状态机处理
class Solution {
    public boolean isNumber(String s) {
            if(s == null || s.length() == 0){
                return false;
            }
            Map[] stage = {
                    new HashMap(){{put('k', 0); put('d',2); put('s', 1); put('t',3);}},  // 0
                    new HashMap(){{put('d', 2); put('t',3);}}, // 1
                    new HashMap(){{put('d', 2);put('t',9);put('e',5);put('k', 8);}}, // 2
                    new HashMap(){{put('d', 4);}}, // 3
                    new HashMap(){{put('d', 4);put('e',5);put('k', 8);}}, // 4
                    new HashMap(){{put('s', 6);put('d',7);}}, // 5
                    new HashMap(){{put('d', 7);}}, // 6
                    new HashMap(){{put('d', 7); put('k', 8);}}, // 7
                    new HashMap(){{put('k', 8);}}, // 8
                    new HashMap(){{put('k', 8);put('d', 4);put('e', 5);}} // 9
            };
            int p = 0;
            for(int i=0; i='0'&&c<='9'){
            return 'd';
        }
        if(c == '.'){
            return 't';
        }
        if(c == ' '){
            return 'k';
        }
        if(c == 'e' || c == 'E'){
            return 'e';
        }
        if(c == '+' || c == '-'){
            return 's';
        }
        return null;
    }
}

4. 把字符串转换成整数力扣

Java 中的整数范围
整数
最小值 -2147483648
最大值 2147483647
public int strToInt(String str) {
        if (str == null || str.length() == 0) {
            return 0;
        }
        int i = 0;
        int count = 0;
        int flag = 1;
        while (i < str.length() && str.charAt(i) == ' ') {
            i++;
        }
        if (i < str.length() && (str.charAt(i) == '+' || str.charAt(i) == '-')) {
            flag = str.charAt(i) == '+' ? 1 : -1;
            i++;
        }
        while (i < str.length()) {
            int tmp = str.charAt(i) - '0';
            if (tmp < 0 || tmp > 9) {
                return count*flag;
            }
            if (count < Integer.MAX_VALUE / 10 || (count == Integer.MAX_VALUE / 10 && tmp <= 7)) {
                count = count * 10 + tmp;
            }else{
                return flag>0?Integer.MAX_VALUE:Integer.MIN_VALUE;
            }
            i++;
        }
        return count*flag;
    }

 反转单词顺序 力扣

// split分割
public String reverseWords(String s) {
        if(s==null ||s.length() == 0){
            return s;
        }
        String[] words = s.split(" ");
        StringBuffer sb = new StringBuffer();
        for(int i = words.length-1; i>=0; i--){
            if(!words[i].equals("")){
                sb.append(words[i]);
                sb.append(" ");
            }
        }
        String result = sb.toString();

        // 注意判断长度
        return result.length()>0?result.substring(0, result.length()-1):"";
    }

// 双指针反转,不去除空格,每个单词反转,再整体反转
public String reverseWords(String s) {
        if (s == null || s.length() == 0) {
            return s;
        }
        char[] chars = s.toCharArray();
        int i = 0;
        int j = 0;
        while (i < chars.length) {
            while (i < chars.length && chars[i] == ' ') {
                i++;
                j++;
            }
            while (j < chars.length && chars[j] != ' ') {
                j++;
            }
            swap(chars, i, j-1);
            i=j;
        }
        swap(chars, 0, chars.length-1);
        return String.valueOf(chars);
    }

第一个只出现一次的字符(LinkedHashMap/普通hash遍历两次)

// 普通哈希
class Solution {
    public char firstUniqChar(String s) {
        HashMap dic = new HashMap<>();
        char[] sc = s.toCharArray();
        for(char c : sc)
            dic.put(c, !dic.containsKey(c));
        for(char c : sc)
            if(dic.get(c)) return c;
        return ' ';
    }
}

// 有序哈希LinedHashMap
class Solution {
    public char firstUniqChar(String s) {
        Map dic = new LinkedHashMap<>();
        char[] sc = s.toCharArray();
        for(char c : sc)
            dic.put(c, !dic.containsKey(c));
        for(Map.Entry d : dic.entrySet()){
           if(d.getValue()) return d.getKey();
        }
        return ' ';
    }
}

二、链表

1.反转链表:用到中间node "next"

public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            ListNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }

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

// 通过两个哈希表,内存占用多
public ListNode copyRandomList(ListNode head) {
        if (head == null) {
            return head;
        }
        Map old2new = Maps.newHashMap();
        Map new2old = Maps.newHashMap();
        ListNode newHead = genNewListNodeByOld(head, old2new, new2old);
        ListNode cur = newHead;
        while (head.next != null) {
            cur.next = genNewListNodeByOld(head.next, old2new, new2old);
            cur = cur.next;
            head = head.next;
        }
        cur = newHead;
        while (cur != null) {
            cur.random = old2new.get(new2old.get(cur).random);
            cur = cur.next;
        }
        return newHead;
    }

    public ListNode genNewListNodeByOld(ListNode oldNode, Map old2New,
                                        Map new2Old) {
        ListNode newNode = new ListNode(oldNode.val);
        old2New.put(oldNode, newNode);
        new2Old.put(newNode, oldNode);
        return newNode;
    }


// 通过链表重构加链表拆分
public ListNode copyRandomList(ListNode head) {
        if (head == null) {
            return head;
        }
        ListNode newHead = head;
        while(head!=null){
            ListNode newNode = new ListNode(head.val);
            newNode.next = head.next;
            head.next = newNode;
            head = head.next.next;
        }
        head = newHead;
        while(head!=null){
            // 注意: 特别处理null!!!
            head.next.random = head.random == null?null:head.random.next; 
            head = head.next.next;
        }
        head = newHead;
        newHead = newHead.next;
        while(head!=null){
            ListNode newNode = head.next;
            head.next = head.next.next;
            // 注意: 特别处理null!!!
            newNode.next = newNode.next == null?null:newNode.next.next; 
            head = head.next;
        }
        return newHead;
    }

删除链表中的一个节点 剑指 Offer 18. 删除链表的节点 - 力扣(LeetCode)

 public ListNode deleteNode(ListNode head, int val) {
        ListNode begin = head;
        ListNode preview = null;
        while (begin != null) {
            if (begin.val == val) {
                if (preview != null) { // 注意判空
                    preview.next = begin.next;
                } else {
                    head = head.next;
                }
            }
            preview = begin;
            begin = begin.next;
        }
        return head;
    }

获取链表倒数第k个节点

// 通过arrayList获取
public ListNode getKthFromEnd(ListNode head, int k) {
        if(head == null){
            return null;
        }
        List nodes = new ArrayList<>();
        while(head!=null){
            nodes.add(head);
            head = head.next;
        }
        if(nodes.size()0){
            head = head.next;
            k--;
        }
        if(head == null&&k>0){
            return null;
        }
        while(head!=null){
            latter = latter.next;
            head = head.next;
        }
        return latter;
    }

合并排序链表

 public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode begin = new ListNode(0);
        ListNode p = begin;
        while(l1!=null && l2!=null){
            if(l1.val<=l2.val){
                begin.next = l1;
                l1 = l1.next;
            }else{
                begin.next = l2;
                l2 = l2.next;
            }
            begin = begin.next;
        }
        while(l1!=null){
            begin.next = l1;
            l1 = l1.next;
            begin = begin.next;
        }
        while(l2!=null){
            begin.next = l2;
            l2 = l2.next;
            begin = begin.next;
        }
        return p.next;
    }

剑指 Offer 52. 两个链表的第一个公共节点  

// 直观方法,两个stack
ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        Stack a = new Stack<>();
        Stack b = new Stack<>();
        for(ListNode head = headA; head !=null; head = head.next){
            a.push(head);
        }
        for(ListNode head = headB; head!=null; head = head.next){
            b.push(head);
        }
        ListNode common = null;
        while(a.size()>0 && b.size()>0 && a.peek() == b.peek()){
            common = a.pop();
            b.pop();
        }
        return common;
    }

// 数学方法,双指针相遇
A走完到common, a+b-c
B走完到common, b+a-c
相等的的点就是重合的点

ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode a = headA;
        ListNode b = headB;
        while(a!=b){
           a = a == null?headB:a.next;
           b = b == null?headA:b.next;
        }
        return a;
    }

三、栈

1.从头到尾打印链表力扣

public int[] reversePrint(ListNode head) {
        if(head == null){
            return new int[0];
        }
        Stack stack = new Stack<>();
        while(head!=null){
            stack.push(head);
            head = head.next;
        }
        int[] vals = new int[stack.size()];
        for(int i = 0; i

两个栈实现队列力扣

class CQueue {
    public static Stack stack1;
    public static Stack stack2;

    public CQueue() {
        stack1 = new Stack<>();
        stack2 = new Stack<>();
    }

    public void appendTail(int value) {
        stack1.push(value);
    }

    public int deleteHead() {
        if (stack2.size() == 0) {
            while (stack1.size() > 0) {
                stack2.push(stack1.pop());
            }
        }
        return stack2.size() > 0 ? stack2.pop() : -1;
    }
}

 包含min函数的栈 力扣

class MinStack {
    Stack mainStack;
    Stack minStack;

    /**
     * initialize your data structure here.
     */
    public MinStack() {
        mainStack = new Stack<>();
        minStack = new Stack<>();
    }

    public void push(int x) {
        mainStack.push(x);
        if (minStack.empty() || x <= minStack.peek()) {
            minStack.push(x);
        }
    }

    public void pop() {
        int x = mainStack.pop();
        if (minStack.size() > 0 && minStack.peek() == x) {
            minStack.pop();
        }
    }

    public int top() {
        return mainStack.peek();
    }

    public int min() {
        return minStack.peek();
    }
}

 栈的压入弹出

剑指 Offer 31. 栈的压入、弹出序列

public boolean validateStackSequences(int[] pushed, int[] popped) {
        if(pushed == null || popped == null || pushed.length != popped.length){
            return false;
        }
        Stack mockStack = new Stack<>();
        int cursorP = 0;
        for(int i = 0; i0 && cursorP

队列

队列最大值(类滑动窗口)
剑指 Offer 59 - II. 队列的最大值

class MaxQueue {
    LinkedList mainQueue;
    LinkedList maxQueue;

    public MaxQueue() {
        mainQueue = new LinkedList();
        maxQueue = new LinkedList();
    }

    public int max_value() {
        if (maxQueue.size() == 0) {
            return -1;
        }
        return maxQueue.peek();
    }

    public void push_back(int value) {

        while (maxQueue.size() > 0 && mainQueue.getLast() < value) {
            maxQueue.removeLast();
        }
        mainQueue.offer(value);
    }

    public int pop_front() {
        int value = mainQueue.isEmpty() ? -1 : mainQueue.poll();
        if (maxQueue.size() != 0 && mainQueue.peek() == value) {
            maxQueue.poll();
        }
        return value;
    }

    public static void main(String args[]) {
        MaxQueue maxQueue = new MaxQueue();
        maxQueue.push_back(1);
        maxQueue.push_back(2);
        maxQueue.max_value();
        maxQueue.pop_front();
        maxQueue.max_value();
    }
}

数组


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

public int[] exchange(int[] nums) {
        if (nums == null || nums.length <= 1) {
            return nums;
        }
        int i = 0;
        int j = nums.length - 1;
        while (i < j) {
            while (i < j && nums[i] % 2 == 1) {
                i++;
            }
            while (i < j && nums[j] % 2 == 0) {
                j--;
            }
            int tmp = nums[i];
            nums[i] = nums[j];
            nums[j] = tmp;
        }
        return nums;
    }

和为s的两个数字 力扣

public int[] twoSum(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return null;
        }
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            if (target == nums[left] + nums[right]) {
                return new int[] {nums[left], nums[right]};
            } else if (target < nums[left] + nums[right]) {
                right--;
            } else {
                left++;
            }
        }
        return null;
    }

滑动窗口最大值 

public int[] maxSlidingWindow(int[] nums, int k) {
        if (nums == null || nums.length == 0) {
            return null;
        }
        List maxList = new ArrayList<>();

        // 队列用于记录最后最大值
        LinkedList q = new LinkedList<>();
        // 用于记录最大值
        Integer max = nums[0];
        // 窗口未满不用移动
        for (int i = 0; i < nums.length && i < k; i++) {
            while (q.size() > 0 && nums[i] > q.getLast()) {
                q.removeLast();
            }
            q.add(nums[i]);
            max = max > nums[i] ? max : nums[i];
        }
        maxList.add(max);
        // 窗口满了以后,每移动一步,判断窗口开始值前一个(i-k)是否为最大值,是则移除
        for (int i = k; i < nums.length; i++) {
            while (q.size() > 0 && nums[i] > q.getLast()) {
                q.removeLast();
            }
            q.add(nums[i]);
            max = max > nums[i] ? max : nums[i];
            if (nums[i - k] == max) {
                q.removeFirst();
                max = q.getFirst();
            }
            maxList.add(max);
        }
        int a[] = new int[maxList.size()];
        for (int i = 0; i < maxList.size(); i++) {
            a[i] = maxList.get(i);
        }
        return a;
    }

螺旋打印数组力扣

public int[] spiralOrder(int[][] matrix) {
        if (matrix == null || matrix.length == 0) {
            return new int[0];
        }
        int rowEnd = matrix.length - 1;
        int colEnd = matrix[0].length - 1;
        int rowBegin = 0;
        int colBegin = 0;
        int r = 0;
        int c = 0;
        int[] result = new int[matrix.length * matrix[0].length];
        int cursor = 0;
        while (rowBegin < rowEnd && colBegin < colEnd) {
            while (c < colEnd) {
                result[cursor++] = matrix[r][c++];
            }
            while (r < rowEnd) {
                result[cursor++] = matrix[r++][c];
            }
            while (c > colBegin) {
                result[cursor++] = matrix[r][c--];
            }
            while (r > rowBegin) {
                result[cursor++] = matrix[r--][c];
            }
            rowBegin++;
            rowEnd--;
            colBegin++;
            colEnd--;
            r = rowBegin;
            c = colBegin;
        }
        if (rowBegin == rowEnd) {
            for (c = colBegin; c <= colEnd; c++) {
                result[cursor++] = matrix[r][c];
            }
        } else if(colBegin == colEnd){
            for (r = rowBegin; r <= rowEnd; r++) {
                result[cursor++] = matrix[r][c];
            }
        }
        return result;
    }

数组的重复数字

 力扣

// 通过哈希表
public int findRepeatNumber(int[] nums) {
        if(nums == null || nums.length == 0){
            return -1;
        }
        Set  numSet = new HashSet<>();
        for(int i = 0;i

 * 排序数组查找数字,个数(二分查找)

剑指 Offer 53 - I. 在排序数组中查找数字 I 

public static int search(int[] nums, int target) {
        if(nums == null || nums.length == 0){
            return 0;
        }
        // 查找右边界
        int end = findBand(nums, target);
        // 查找左边界
        int begin = findBand(nums, target-1);
        return end-begin;
    }
    public static int findBand(int nums[], int target){
        int left = 0;
        int right = nums.length-1;
        while(left<=right){
            int mid = (left+right)/2;
            if(nums[mid]<=target){
                left = mid+1;
            }else {
                right = mid-1;
            }
        }
        return left;
    }

0-n-1中缺失的数字(二分查找)

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

public int missingNumber(int[] nums) {
        if(nums == null || nums.length == 0){
            return -1;
        }
        int left = 0;
        int right = nums.length-1;
        while(left<=right){
            int mid = (left+right)/2;
            if(nums[mid] == mid){
                left = mid+1;
            }else{
                right = mid-1;
            }
        }
        return left;
    }

二维数组中的查找

public boolean findNumberIn2DArray(int[][] matrix, int target) {
        if(matrix == null || matrix.length == 0){
            return false;
        }
        int i = matrix[0].length-1;
        int j = 0;
        while(i>=0 && jtarget){
                i--;
            }else if(matrix[j][i]

旋转数组最小值(二分查找,注意边界)

力扣

public int minArray(int[] numbers) {
        if(numbers == null || numbers.length == 0){
            return -1;
        }
        int left = 0;
        int right = numbers.length-1;
        while(leftnumbers[right]){
                left = mid+1;
            // 小于,可能为最小值或在左边
            }else if(numbers[mid]

从上到下打印二叉树

public int[] levelOrder(TreeNode root) {
        if(root == null){
            return new int[0];
        }
        List valList = new ArrayList<>();
        Queue  tmpQueue = new LinkedList<>();
        tmpQueue.offer(root);
        
        while(tmpQueue.size()>0){
            TreeNode node = tmpQueue.poll();
            valList.add(node.val);
            if(node.left!=null){
                tmpQueue.offer(node.left);
            }
            if(node.right!=null){
                tmpQueue.offer(node.right);
            }
        }

        int[] result = new int[valList.size()];
        for(int i = 0; i

从上到下分层打印二叉树

力扣

public List> levelOrder(TreeNode root) {
        List> result = new ArrayList<>();
        if(root==null){
            return result;
        }
        Queue queue1 = new LinkedList<>();
        Queue queue2 = new LinkedList<>();
        queue1.offer(root);
        List tmp = new ArrayList<>();
        while(queue1.size()>0){
            TreeNode curNode = queue1.poll();
            tmp.add(curNode.val);
            if(curNode.left!=null){
                queue2.offer(curNode.left);
            }
            if(curNode.right!=null){
                queue2.offer(curNode.right);
            }
            if(queue1.size() == 0){
                result.add(tmp);
                tmp = new ArrayList<>();
                Queue tmpp = queue1;
                queue1 = queue2;
                queue2 = tmpp;
            }
        }
        return result;
    }

* 之字形分层打印二叉树 力扣

public List> levelOrder(TreeNode root) {
        List> result = new ArrayList<>();
        if(root == null){
            return result;
        }
        // 注意此处申明,必须是LinkedList才有addFirst方法!!
        LinkedList tmpResult = new LinkedList<>();
        boolean flag = true;
        Queue queue1 = new LinkedList<>();
        Queue queue2 = new LinkedList<>();
        queue1.offer(root);
        while(queue1.size()>0){
            // 之字形,在上一题的基础上,反正打印就行了,不用转换队列写入顺序!!
            root = queue1.poll();
            if(flag){
                tmpResult.add(root.val);
            }else{
                tmpResult.addFirst(root.val);
            }
            if(root.left!=null){
                queue2.offer(root.left);
            }
            if(root.right!=null){
                queue2.offer(root.right);
            }
                
            if(queue1.size() == 0){
                result.add(tmpResult);
                tmpResult = new LinkedList<>();
                queue1 = queue2;
                queue2 = new LinkedList<>();
                flag = !flag;
            }
        }
        return result;
    }

* 判断子树 力扣

public boolean isSubStructure(TreeNode A, TreeNode B) {
        // 由于约定空树不为子树,因此需为不等于null,三种可能:相同树,为右子树,为左子树
        return (A!=null && B!=null &&(isSameTree(A, B)||isSubStructure(A.left, B)||isSubStructure(A.right, B)));
    }

    // 相同树, 
    public boolean isSameTree(TreeNode A, TreeNode B) {
        // B为null,说明递归到头了,返回true
        if(B == null){
            return true;
        }
        // 否则,A为null,说明A cover不住B,返回false
        if(A == null || A.val!=B.val){
            return false;
        }
        // 循环判断左右节点
        return isSameTree(A.left, B.left) && isSameTree(A.right, B.right);
    }

你可能感兴趣的:(算法,leetcode,java)