用LeetCode学习数据结构和算法

294 阅读5分钟

大二学生,暑假无事,记录LeetCode上的经典算法题以供日后复习

题目来源:力扣(LeetCode)

数组 & 链表

1. 反转链表

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode curr = head;
        ListNode prev = null;
        while (curr != null) {
            ListNode nextTemp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = nextNode;
        }
        return prev;
    }
}

2. 两两交换链表中的节点

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode prev = new ListNode(0);
        prev.next = head;
        ListNode temp = prev;
        while (temp.next != null && temp.next.next != null) {
            ListNode left = temp.next;
            ListNode right = left.next;
            temp.next = right;
            left.next = right.next;
            right.next = left;
            temp = left;
        }
        return prev.next;
    }
}

3. 环形链表

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode fast = head, slow = head;
        while (fast != null && slow != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) return true;
        }
        return false;
    }
}

4. 环形链表 II

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) {
        HashSet<ListNode> hashSet = new HashSet<>();
        ListNode curr = head;
        while (curr != null) {
            if (hashSet.contains(curr)) return curr;
            hashSet.add(curr);
            curr = curr.next;
        }
        return null;
    }
}

5. K 个一组翻转链表

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        int i = k;
        ListNode curr = head;
        ListNode[] stack = new ListNode[k];
        while (k > 0) {
            stack[i - k] = curr;
            if (curr != null) curr = curr.next;
            else return head;
            k--;
        }
        while (k < i - 1) {
            k++;
            stack[i - k].next = stack[i - k - 1];
        }
        stack[0].next = reverseKGroup(curr, k + 1);
        return stack[i - 1];
    }
}

栈 & 队列

6. 比较含退格的字符串

  • 我的Java代码:
class Solution {
    public boolean backspaceCompare(String S, String T) {
        Stack<Character> s = new Stack<>();
        Stack<Character> t = new Stack<>();
        for (int i = 0; i < S.length(); i++) {
            if (S.charAt(i) != '#') s.push(S.charAt(i));
            else if (!s.isEmpty()) s.pop();
        }
        for (int i = 0; i < T.length(); i++) {
            if (T.charAt(i) != '#') t.push(T.charAt(i));
            else if (!t.isEmpty()) t.pop();
        }
        if (s.size() != t.size()) return false;
        for (int i = 0; i < s.size(); i++)
            if (s.pop() != t.pop()) return false;
        return true;
    }
}

7. 有效的括号

class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        HashMap<Character, Character> hm = new HashMap<>();
        hm.put(')', '(');
        hm.put(']', '[');
        hm.put('}', '{');
        int n = s.length();
        for (int i = 0; i < n; i++) {
            if (!hm.containsKey(s.charAt(i)))
                stack.push(s.charAt(i));
            else if (stack.isEmpty() || stack.pop() != hm.get(s.charAt(i)))
                return false;
        }
        return stack.isEmpty();
    }
}

8. 用栈实现队列

class MyQueue {
    Stack<Integer> inputStack;
    Stack<Integer> outputStack;

    /**
     * Initialize your data structure here.
     */
    public MyQueue() {
        inputStack = new Stack<>();
        outputStack = new Stack<>();
    }

    /**
     * Push element x to the back of queue.
     */
    public void push(int x) {
        inputStack.push(x);
    }

    /**
     * Removes the element from in front of queue and returns that element.
     */
    public int pop() {
        convert();
        return outputStack.pop();
    }

    /**
     * Get the front element.
     */
    public int peek() {
        convert();
        return outputStack.peek();
    }

    /**
     * Returns whether the queue is empty.
     */
    public boolean empty() {
        return inputStack.isEmpty() && outputStack.isEmpty();
    }

    public void convert() {
        if (outputStack.isEmpty())
            while (!inputStack.isEmpty())
                outputStack.push(inputStack.pop());
    }
}
/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * boolean param_4 = obj.empty();
 */

9. 用队列实现栈

import java.util.concurrent.LinkedBlockingQueue;
class MyStack {
    Queue<Integer> queue;

    /**
     * Initialize your data structure here.
     */
    public MyStack() {
        queue = new LinkedBlockingQueue<>();

    }

    /**
     * Push element x onto stack.
     */
    public void push(int x) {
        queue.add(x);
        int n = queue.size();
        while (n > 1) {
            queue.add(queue.remove());
            n--;
        }
    }

    /**
     * Removes the element on top of the stack and returns that element.
     */
    public int pop() {
        return queue.remove();
    }

    /**
     * Get the top element.
     */
    public int top() {
        return queue.peek();
    }

    /**
     * Returns whether the stack is empty.
     */
    public boolean empty() {
        return queue.isEmpty();
    }
}

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

优先队列

10. 数据流中的第K大元素

  • 我的Java代码:
class KthLargest {
    PriorityQueue<Integer> q;
    int k;

    public KthLargest(int k, int[] nums) {
        this.k = k;
        q = new PriorityQueue<>(k);
        for (int n : nums)
            add(n);
    }

    public int add(int val) {
        if (q.size() < k)
            q.offer(val);
        else if (q.peek() < val) {
            q.poll();
            q.offer(val);
        }
        return q.peek();
    }
}

/**
 * Your KthLargest object will be instantiated and called as such:
 * KthLargest obj = new KthLargest(k, nums);
 * int param_1 = obj.add(val);
 */

11. 滑动窗口最大值

class Solution {
    ArrayDeque<Integer> deq = new ArrayDeque<Integer>();
    int[] nums;

    public void clean_deque(int i, int k) {
        // remove indexes of elements not from sliding window
        if (!deq.isEmpty() && deq.getFirst() == i - k)
            deq.removeFirst();

        // remove from deq indexes of all elements
        // which are smaller than current element nums[i]
        while (!deq.isEmpty() && nums[i] > nums[deq.getLast()])
            deq.removeLast();
    }

    public int[] maxSlidingWindow(int[] nums, int k) {
        int n = nums.length;
        if (n * k == 0) return new int[0];
        if (k == 1) return nums;

        // init deque and output
        this.nums = nums;
        int max_idx = 0;
        for (int i = 0; i < k; i++) {
            clean_deque(i, k);
            deq.addLast(i);
            // compute max in nums[:k]
            if (nums[i] > nums[max_idx]) max_idx = i;
        }
        int[] output = new int[n - k + 1];
        output[0] = nums[max_idx];

        // build output
        for (int i = k; i < n; i++) {
            clean_deque(i, k);
            deq.addLast(i);
            output[i - k + 1] = nums[deq.getFirst()];
        }
        return output;
    }
}

映射 & 集合

12. 有效的字母异位词

class Solution {
    public boolean isAnagram(String s, String t) {
        if (s.length() != t.length()) {
            return false;
        }
        int[] counter = new int[26];
        for (int i = 0; i < s.length(); i++) {
            counter[s.charAt(i) - 'a']++;
            counter[t.charAt(i) - 'a']--;
        }
        for (int count : counter) {
            if (count != 0) {
                return false;
            }
        }
        return true;
    }
}

13. 两数之和

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

14. 三数之和

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int len = nums.length;
        List<List<Integer>> ans = new ArrayList<>();
        if (nums == null || len < 3) return ans;
        Arrays.sort(nums);// sort the array
        for (int i = 0; i < len; i++) {
            // if the current number is greater than 0, the sum of the three must be greater than 0, so end the loop
            if (nums[i] > 0) break;
            if (i > 0 && nums[i] == nums[i - 1]) continue;// get rid of duplicate
            int left = i + 1;
            int right = len - 1;
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum == 0) {
                    ans.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    while (left < right && nums[left] == nums[left + 1]) left++;// get rid of duplicate
                    while (left < right && nums[right] == nums[right - 1]) right--;// get rid of duplicate
                    left++;
                    right--;
                } else if (sum < 0) left++;
                else right--;
            }
        }
        return ans;
    }
}

15. 四数之和

  • 我的Java代码:
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> ans = new LinkedList<>();
        int len = nums.length;
        if (nums == null || len < 4) return ans;
        Arrays.sort(nums);
        for (int i = 0; i < len - 3; i++) {
            if (nums[i] > 0 && nums[i] > target) break;
            for (int j = i + 1; j < len - 2; j++) {
                int left = j + 1;
                int right = len - 1;
                while (left < right) {
                    int sum = nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum == target) {
                        if (!ans.contains(Arrays.asList(nums[i], nums[j], nums[left], nums[right])))
                            ans.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        while (left < right && nums[left] == nums[left + 1]) left++;
                        while (left < right && nums[right] == nums[right - 1]) right--;
                        left++;
                        right--;
                    } else if (sum < target) left++;
                    else right--;
                }
            }
        }
        return ans;
    }
}

树 & 二叉树 & 二叉搜索树

16. 验证二叉搜索树