【急】手撕代码高频

https://www.cnblogs.com/guoyaohua/p/8600214.html

力扣大神
在这里插入图片描述

冒泡

/**
     * 冒泡排序
     *
     * @param array
     * @return
     */
    public static int[] bubbleSort(int[] array) {
        if (array.length == 0)
            return array;
        for (int i = 0; i < array.length; i++)
            for (int j = 0; j < array.length - 1 - i; j++)
                if (array[j + 1] < array[j]) {
                    int temp = array[j + 1];
                    array[j + 1] = array[j];
                    array[j] = temp;
                }
        return array;
    }

选择排序

/**
     * 选择排序
     * @param array
     * @return
     */
    public static int[] selectionSort(int[] array) {
        if (array.length == 0)
            return array;
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;
            for (int j = i; j < array.length; j++) {
                if (array[j] < array[minIndex]) //找到最小的数
                    minIndex = j; //将最小数的索引保存
            }
            int temp = array[minIndex];
            array[minIndex] = array[i];
            array[i] = temp;
        }
        return array;
    }

插入排序

/**
     * 插入排序
     * @param array
     * @return
     */
    public static int[] insertionSort(int[] array) {
        if (array.length == 0)
            return array;
        int current;
        for (int i = 0; i < array.length - 1; i++) {
            current = array[i + 1];
            int preIndex = i;
            while (preIndex >= 0 && current < array[preIndex]) {
                array[preIndex + 1] = array[preIndex];
                preIndex--;
            }
            array[preIndex + 1] = current;
        }
        return array;
    }

希尔

/**
     * 希尔排序
     *
     * @param array
     * @return
     */
    public static int[] ShellSort(int[] array) {
        int len = array.length;
        int temp, gap = len / 2;
        while (gap > 0) {
            for (int i = gap; i < len; i++) {
                temp = array[i];
                int preIndex = i - gap;
                while (preIndex >= 0 && array[preIndex] > temp) {
                    array[preIndex + gap] = array[preIndex];
                    preIndex -= gap;
                }
                array[preIndex + gap] = temp;
            }
            gap /= 2;
        }
        return array;
    }

归并排序

/**
     * 归并排序
     *
     * @param array
     * @return
     */
    public static int[] MergeSort(int[] array) {
        if (array.length < 2) return array;
        int mid = array.length / 2;
        int[] left = Arrays.copyOfRange(array, 0, mid);
        int[] right = Arrays.copyOfRange(array, mid, array.length);
        return merge(MergeSort(left), MergeSort(right));
    }
    /**
     * 归并排序——将两段排序好的数组结合成一个排序数组
     *
     * @param left
     * @param right
     * @return
     */
    public static int[] merge(int[] left, int[] right) {
        int[] result = new int[left.length + right.length];
        for (int index = 0, i = 0, j = 0; index < result.length; index++) {
            if (i >= left.length)
                result[index] = right[j++];
            else if (j >= right.length)
                result[index] = left[i++];
            else if (left[i] > right[j])
                result[index] = right[j++];
            else
                result[index] = left[i++];
        }
        return result;
    }

快速排序

import java.util.Random;

public class Solution {

    // 快速排序 1:基本快速排序

    /**
     * 列表大小等于或小于该大小,将优先于 quickSort 使用插入排序
     */
    private static final int INSERTION_SORT_THRESHOLD = 7;

    private static final Random RANDOM = new Random();


    public int[] sortArray(int[] nums) {
        int len = nums.length;
        quickSort(nums, 0, len - 1);
        return nums;
    }

    private void quickSort(int[] nums, int left, int right) {
        // 小区间使用插入排序
        if (right - left <= INSERTION_SORT_THRESHOLD) {
            insertionSort(nums, left, right);
            return;
        }
		//细节
        int pIndex = partition(nums, left, right);
        quickSort(nums, left, pIndex - 1);
        quickSort(nums, pIndex + 1, right);
    }

    /**
     * 对数组 nums 的子区间 [left, right] 使用插入排序
     *
     * @param nums  给定数组
     * @param left  左边界,能取到
     * @param right 右边界,能取到
     */
    private void insertionSort(int[] nums, int left, int right) {
        for (int i = left + 1; i <= right; i++) {
            int temp = nums[i];
            int j = i;
            while (j > left && nums[j - 1] > temp) {
                nums[j] = nums[j - 1];
                j--;
            }
            nums[j] = temp;
        }
    }

    private int partition(int[] nums, int left, int right) {
        int randomIndex = RANDOM.nextInt(right - left + 1) + left;
        swap(nums, left, randomIndex);

        // 基准值
        int pivot = nums[left];
        int lt = left;
        // 循环不变量:
        // all in [left + 1, lt] < pivot
        // all in [lt + 1, i) >= pivot
        for (int i = left + 1; i <= right; i++) {
            if (nums[i] < pivot) {
                lt++;
                swap(nums, i, lt);
            }
        }
        swap(nums, left, lt);
        return lt;
    }

    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

堆排序

public class Solution {

    public int[] sortArray(int[] nums) {
        int len = nums.length;
        // 将数组整理成堆
        heapify(nums);

        // 循环不变量:区间 [0, i] 堆有序
        for (int i = len - 1; i >= 1; ) {
            // 把堆顶元素(当前最大)交换到数组末尾
            swap(nums, 0, i);
            // 逐步减少堆有序的部分
            i--;
            // 下标 0 位置下沉操作,使得区间 [0, i] 堆有序
            siftDown(nums, 0, i);
        }
        return nums;
    }

    /**
     * 将数组整理成堆(堆有序)
     *
     * @param nums
     */
    private void heapify(int[] nums) {
        int len = nums.length;
        // 只需要从 i = (len - 1) / 2 这个位置开始逐层下移
        for (int i = (len - 1) / 2; i >= 0; i--) {
            siftDown(nums, i, len - 1);
        }
    }

    /**
     * @param nums
     * @param k    当前下沉元素的下标
     * @param end  [0, end] 是 nums 的有效部分
     */
    private void siftDown(int[] nums, int k, int end) {
        while (2 * k + 1 <= end) {
            int j = 2 * k + 1;
            if (j + 1 <= end && nums[j + 1] > nums[j]) {
                j++;
            }
            if (nums[j] > nums[k]) {
                swap(nums, j, k);
            } else {
                break;
            }
            k = j;
        }
    }

    private void swap(int[] nums, int index1, int index2) {
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

写了好多忘了保存又打开了新的一个,之前写的都没了

25. K 个一组翻转链表 9

使用递归太巧妙了,这是我做过的用递归最好用的题之一,迭代的细节很多,用递归生生做成了一道简单题。

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head==null) return null;
        ListNode cur = head;
        int i = k;
        // 先遍历找到下一段的开头
        while(i>0&&cur!=null){
            cur = cur.next;
            i--;
        }
        // 如果没有到k个,那么原顺序返回
        if(i>0) return head;
        // 关键在于这个位置,返回值拼接到当前段翻转后的尾结点即可
        // 而尾结点就是原链表在当前段的头
        ListNode pre = reverseKGroup(cur,k);
        i = k;
        while(i>0){
            ListNode temp = head.next;
            head.next = pre;
            pre = head;
            head = temp;
            i--; 
        }
        return pre;
    }
}

3. 无重复字符的最长子串 8

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int len = s.length();
        int[] dic = new int[128];
        Arrays.fill(dic, -1);
        int cur = 0;
        int max = 0;
        for (int i = 0; i < len; i++) {
            int thisC = i - dic[s.charAt(i)];
            // thisC是当前字符自从上次出现后的最大长度
            if(thisC > cur){
                cur++;
            }else{
                cur = thisC;
            }
            max = Math.max(max, cur);
            dic[s.charAt(i)] = i;
        }
        return max;
    }
}

102. 二叉树的层序遍历 6

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        Deque<TreeNode> q = new LinkedList<>();
        q.add(root);
        while(!q.isEmpty()){
            int size = q.size();
            List<Integer> t = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                TreeNode cur = q.poll();
                if(cur != null){
                    t.add(cur.val);
                    q.add(cur.left);
                    q.add(cur.right);
                }
            }
            if(t.size() > 0) res.add(t);
        }
        return res;
    }
}

124. 二叉树中的最大路径和 6

class Solution {
    private int res = Integer.MIN_VALUE;
    public int maxPathSum(TreeNode root) {
         helper(root);
         return res;
    }
    // 返回的是以root的值为头节点的最大的路径
    private int helper(TreeNode root){
        if(root==null) return 0;
        int le = Math.max(0, helper(root.left));
        int ri = Math.max(0, helper(root.right));
        res = Math.max(res, le + ri + root.val);
        return root.val + Math.max(le, ri);
    }
}

206. 反转链表 6

在这里插入图片描述

class Solution {
    public ListNode reverseList(ListNode head) {
    //迭代
        ListNode pre = null;
        while (head != null){
            ListNode temp = head.next;
            head.next = pre;
            pre = head;
            head = temp;
        }
        return pre;
    }
}

15. 三数之和 6

动态双指针,注意双指针是哪俩。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        for(int k = 0; k < nums.length-2; k++){
            if(nums[k]>0) break;
            if(k>0 && nums[k]==nums[k-1]) continue;

            int i = k + 1, j = nums.length-1;
            while(i < j){
                int sum = nums[i]+nums[j]+nums[k];
                if(sum<0){
                    while(i<j && nums[i] == nums[++i]){
                    }
                }else if(sum>0){
                    while(i<j && nums[j] == nums[--j]){
                    }                
                }else{
                    res.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j])));
                    while(i<j && nums[i] == nums[++i]){
                    }                    
                    while(i<j && nums[j] == nums[--j]){
                    }                      
                } 
                }
            }
               return res;
        }
    }

146. LRU缓存机制 6

  • map和双向链表来保存
  • 对外暴露get和put的方法,参数是int和<int,int>调用add和remove的参数是Node
  • get的逻辑:
  • map中是否有node
  • 有的话得到node
  • 在链表中移除node
  • 在链表末尾增加node
  • 返回node的值
  • put的逻辑
  • 先看原map中有没有这个值,有的话移除
  • 看下map的大小是否超出容量,超的话将head移除
class LRUCache {
    Node head = new Node(0, 0), tail = new Node(0, 0);
    Map<Integer, Node> map = new HashMap<>();
    int max_len;
    public LRUCache(int capacity) {
        max_len = capacity;
        // 建立双链表
        head.next = tail;
        tail.prev = head;
    }
    public int get(int key) {
        if (map.containsKey(key)) {
            Node node = map.get(key);
            remove(node);
            add(node);
            return node.value;
        } else
            return -1;
    }
    public void put(int key, int value) {
        if (map.containsKey(key)) {
            remove(map.get(key));
        }
        // 把表头位置节点删除(说明最近的数据值)
        if (map.size() == max_len) {
            remove(head.next);
        }
        add(new Node(key, value));
    }
    // 删除链表
    private void remove(Node node) {
        map.remove(node.key);
        // 删除节点
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }

    // 加在链表尾
    private void add(Node node) {
        map.put(node.key, node);
        Node pre_tail = tail.prev;
        node.next = tail;
        tail.prev = node;
        pre_tail.next = node;
        node.prev = pre_tail;
    }

    // 创建双向链表
    class Node {
        Node prev, next;
        int key, value;

        Node(int _key, int _value) {
            key = _key;
            value = _value;
        }
    }
}

作者:powcai
链接:https://leetcode-cn.com/problems/lru-cache/solution/pythonde-ordereddict-huo-zhe-ha-xi-shuang-xiang-li/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

215. 数组中的第K个最大元素 5

使用优先队列。

    public int findKthLargest(int[] nums, int k) {
        final PriorityQueue<Integer> queue = new PriorityQueue<>();
        for (int val : nums) {
            queue.add(val);
            if (queue.size() > k)
                queue.poll();
        }
        return queue.peek();
    }

快排思路

class Solution {
    private static Random random = new Random(System.currentTimeMillis());
    public int findKthLargest(int[] nums, int k) {
        int index = nums.length - k;
        int left = 0;
        int right =  nums.length - 1;
        //因为一定有第K大的值所以使用死循环也可以
        while (true){
            int temp = partition(nums, left, right);
            if(temp == index) {return nums[index];}
            else if (temp < index){
                left = index + 1;                
            }else{
                right = index - 1;
            }
        }
    }
    //partition的作用,将所有小于第一个的元素放到第一个元素的左边并且返回第一个元素(没随机交换时)
    private int partition(int[] nums, int start, int end) {
        if (end > start) {
            int randomIndex = start + 1 + random.nextInt(end - start);
            swap(nums, start, randomIndex);
        }
        int piviot = nums[start];
        int j = start;
        for (int i = start + 1; i <= end; i++) {
            //到底是小于等于还是小于?
             if(nums[i] <  piviot) {
                 j++;
                 swap(nums,i,j);
             }
        }
        swap(nums,start,j);
        return j;
    }

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

2. 两数相加 5

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        int c = 0;
        ListNode res = new ListNode(-1);
        ListNode cur = res;
        while(l1 != null && l2 != null){
            int sum = l1.val + l2.val + c;
            c = sum/10;
            cur.next = new ListNode(sum%10);
            l1 = l1.next;
            l2 = l2.next;
            cur = cur.next;
        }
        while(l1 != null){
            int sum = l1.val + c;
            c = sum/10;
            cur.next = new ListNode(sum%10);
            l1 = l1.next;
            cur = cur.next;
        }
        while(l2 != null){
            int sum = l2.val + c;
            c = sum/10;
            cur.next = new ListNode(sum%10);
            l2 = l2.next;
            cur = cur.next;
        }
        if(c > 0)  cur.next = new ListNode(c);
        return res.next;
    }
}

141. 环形链表 5

public class Solution {
    public boolean hasCycle(ListNode head) {
        ListNode f = head;
        ListNode s = head;
        while(f != null && f.next != null){
            f = f.next.next;
            s = s.next;
            if(f == s){
                return true;
            }
        }
        return false;
    }
}

234. 回文链表 5

双指针法。

class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head == null || head.next == null)
            return true;
        ListNode fast = head;
        ListNode slow = head;
        ListNode pre = null;
        ListNode temp = null; 
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            temp = slow.next;
            slow.next = pre;
            pre = slow;
            slow = temp;
        }
        //此时pre是翻转后的头节点,
        
        //一下是节点个数为奇数的情况
        if(fast != null){
            slow = slow.next;
        }
        while(pre != null){
            if(pre.val != slow.val){
                return false;
            }
            pre = pre.next;
            slow = slow.next;
        }
        return true;
    }
}

155. 最小栈 4

  • 使用两个栈
  • 当push的时候,先判断当前值和辅助栈栈顶相比谁小,当前小泽直接压入,辅助栈顶小则再次压入辅助栈顶
import java.util.Stack;

public class MinStack {

    // 数据栈
    private Stack<Integer> data;
    // 辅助栈
    private Stack<Integer> helper;

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

    // 思路 1:数据栈和辅助栈在任何时候都同步

    public void push(int x) {
        // 数据栈和辅助栈一定会增加元素
        data.add(x);
        if (helper.isEmpty() || helper.peek() >= x) {
            helper.add(x);
        } else {
            helper.add(helper.peek());
        }
    }

    public void pop() {
        // 两个栈都得 pop
        if (!data.isEmpty()) {
            helper.pop();
            data.pop();
        }
    }

    public int top() {
        if(!data.isEmpty()){
            return data.peek();
        }
        throw new RuntimeException("栈中元素为空,此操作非法");
    }

    public int getMin() {
        if(!helper.isEmpty()){
            return helper.peek();
        }
        throw new RuntimeException("栈中元素为空,此操作非法");
    }
}

105. 从前序与中序遍历序列构造二叉树 4

public TreeNode buildTree(int[] preorder, int[] inorder) {
    return buildTreeHelper(preorder,  inorder, (long)Integer.MAX_VALUE + 1);
}
int pre = 0;
int in = 0;
private TreeNode buildTreeHelper(int[] preorder, int[] inorder, long stop) {
    //到达末尾返回 null
    if(pre == preorder.length){
        return null;
    }
    //到达停止点返回 null
    //当前停止点已经用了,in 后移
    if (inorder[in] == stop) {
        in++;
        return null;
    }
    int root_val = preorder[pre++];
    TreeNode root = new TreeNode(root_val);   
    //左子树的停止点是当前的根节点
    root.left = buildTreeHelper(preorder,  inorder, root_val);
    //右子树的停止点是当前树的停止点
    root.right = buildTreeHelper(preorder, inorder, stop);
    return root;
}

作者:windliang
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by--22/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

相关:
LeetCode889 根据前序和后序遍历构造二叉树
LeetCode105 从前序与中序遍历序列构造二叉树
LeetCode106 从中序与后序遍历序列构造二叉树

33. 搜索旋转排序数组 4

我喜欢的二分法模板:

  • 边界左右闭
  • 循环条件小于
  • 返回有前判断
  • 寻找左边界,mid中间偏左
  • 寻找右边界,mid中间偏右
class Solution {
    public int search(int[] nums, int target) {
        if(nums.length == 0) return -1;
        int left = 0;
        int right = nums.length - 1;
        int mid = left + (right-left)/2;

        while(left < right){
            if(nums[mid] == target){
                return mid;
            }

            if(nums[left] <= nums[mid]){  //左边升序
                if(target >= nums[left] && target <= nums[mid]){//在左边范围内
                    right = mid;
                }else{//只能从右边找
                    left = mid+1;
                }

            }else{ //右边升序
                if(target >= nums[mid] && target <= nums[right]){//在右边范围内
                    left = mid ;
                }else{//只能从左边找
                    right = mid - 1;
                }

            }
            mid = left + (right-left)/2;
        }
        if(nums[left] == target) return left;
        return -1;  //没找到
    }
}

160. 相交链表 4

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode l1 = headA;
        ListNode l2 = headB;
        while(l1 != l2){
            l1 = l1 == null ? headB : l1.next;
            l2 = l2 == null ? headA : l2.next;
        }
        return l1;
    }
}

128. 最长连续序列 4

经典做法:对于

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int num : nums) set.add(num);
        int res = 0;
        for (int num : nums){
            if(!set.contains(num - 1));
            //如果包含的话,在num - 1时候就计算过了
            int temp = 1;
            while(set.contains(num + temp)){
                temp++;
            }
            res = Math.max(res, temp);             
        }
        return res;
    }
}

103. 二叉树的锯齿形层次遍历 4

class Solution {
    public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
        Deque<TreeNode> q = new LinkedList<>();
        List<List<Integer>> res = new ArrayList<>();
        if(root == null) return res;        
        q.add(root);
        boolean isForward  = true;
        while(!q.isEmpty()){
            int size = q.size();
            Deque<Integer> temp = new LinkedList<>();
            while(size-- > 0){
                TreeNode top = q.poll();
                if(isForward){
                    temp.add(top.val);
                }
                else{
                    temp.addFirst(top.val);
                }
                if(top.left != null){
                    q.add(top.left);
                }
                if (top.right != null){
                    q.add(top.right);
                }
            }
            isForward = !isForward;
            res.add(new ArrayList<>(temp));
        }
        return res;
    }
}

113. 路径总和 II 4

  • 树的dfs比较简单,因为不会出现重复访问的情况,不必维持记忆数组。
  • 不要在空节点处添加路径,因为会添加两次
class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        List<List<Integer>> res = new ArrayList<>();
        bfs(res,new ArrayList<Integer>(),root,sum);
        return res;
    }

    private void bfs(List<List<Integer>> res, ArrayList<Integer> temp, TreeNode root, int sum) {
        if(root == null) return;        
        if(root.left == null && root.right == null){
            ArrayList<Integer> path = new ArrayList<>(temp);
            path.add(root.val);
            sum -= root.val;
            if(sum == 0) res.add(path);
            return;
        }
        temp.add(root.val);
        bfs(res, temp, root.left, sum - root.val);
        bfs(res, temp, root.right, sum - root.val);
        temp.remove(temp.size() - 1);
    }
}

121.买卖股票 3

  • 只需要维护个左侧最小值即可,最小值的更新是和当前比一下。
  • 维护历史最大收益,然后利用当前值与最小值试图更新最大收益
class Solution {
    public int maxProfit(int[] prices) {
        //一个指针记录大小,;另一个记录res
        int pre = Integer.MAX_VALUE;
        int res = 0;
        for (int i = 0; i < prices.length; i++) {
            pre = Math.min(pre, prices[i]);
            res  = Math.max(prices[i] - pre, res);
        }
        return res;
    }
}

108. 将有序数组转换为二叉搜索树 3

return root的模板

BST的中序遍历是升序的,因此本题等同于根据中序遍历的序列恢复二叉搜索树。因此我们可以以升序序列中的任一个元素作为根节点,以该元素左边的升序序列构建左子树,以该元素右边的升序序列构建右子树,这样得到的树就是一棵二叉搜索树啦~
又因为本题要求高度平衡,因此我们需要选择升序序列的中间元素作为根节点奥

作者:sweetiee
链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/solution/jian-dan-di-gui-bi-xu-miao-dong-by-sweetiee/
来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return dfs(nums, 0, nums.length - 1);
    }

    private TreeNode dfs(int[] nums, int s, int e) {
        if (s > e) return null;
        int m = s + (e - s ) / 2;
        TreeNode root = new TreeNode(nums[m]);
        root.left = dfs(nums, s, m - 1);
        root.right = dfs(nums, m + 1, e);
        return root;
    }
}

88. 合并两个有序数组 3

和链表思路一样

162. 寻找峰值 3

因为左右边界都是无穷小,所以可以用二分搜索的方法,向上爬坡即可

class Solution {
    public int findPeakElement(int[] nums) {
        //找峰值,使用二分查找中间值小于右侧值说明在上升
        int i = 0;
        int j = nums.length-1;
        while(i < j){
            int m = i + (j - i)/2;
            if(nums[m] < nums[m+1]){
                i = m + 1;
            }else j = m;            
        }
        return i;
    }
}

56. 合并区间 3

  • 要熟悉使用return Arrays.copyOf(res, idx + 1);!感觉就像使用list一样!
  • 记住else更新结束值要使用最大的,不要直接赋当前值
class Solution {
    public int[][] merge(int[][] intervals) {
        // 先按照区间起始位置排序
        Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);
        // 遍历区间
        int[][] res = new int[intervals.length][2];
        int idx = -1;
        for (int[] interval: intervals) {
            // 如果结果数组是空的,或者当前区间的起始位置 > 结果数组中最后区间的终止位置,
            // 则不合并,直接将当前区间加入结果数组。
            if (idx == -1 || interval[0] > res[idx][1]) {
                res[++idx] = interval;
            } else {
                // 反之将当前区间合并至结果数组的最后区间
                res[idx][1] = Math.max(res[idx][1], interval[1]);
            }
        }
        return Arrays.copyOf(res, idx + 1);
    }
}

作者:sweetiee
链接:https://leetcode-cn.com/problems/merge-intervals/solution/chi-jing-ran-yi-yan-miao-dong-by-sweetiee/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

110. 平衡二叉树 3

探究整棵树的是否满足性质,常用这种方法

  • 对于左右子树直接递归调用
  • 对本节点进行判断(判断方法还可能是递归)
class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root == null) return true;
        return (Math.abs(height(root.left) - height(root.right)) <= 1) && isBalanced(root.left) && isBalanced(root.right);
    }

    private int height(TreeNode root) {
        if(root == null) return 0;

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

236. 二叉树的最近公共祖先 3

一般题目中,递归函数结果是符合函数要求的结果,只不过问题规模缩小了。而本题目中,当lowestCommonAncestor的第一个参数

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root==q) return root;
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        if(left == null && right==null){
            return null;
        }
        if(left==null) return right; //说明下一级递归中的root不是null;
        if(right==null) return left;
        return root;
        
    }
}

322. 零钱兑换 3

背包

class Solution {
    public int coinChange(int[] coins, int amount) {
        //01背包
        int[] dp = new int[amount + 1];
        Arrays.fill(dp, amount + 1);
        dp[0] = 0;
        for (int i = 0; i <= amount; i++) {
            for (int j = 0; j < coins.length; j++) {            
                if(i >= coins[j]){
                    dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return dp[amount] == amount + 1 ? -1 :dp[amount];
    }
}

101. 对称二叉树 3

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return  dfs(root,root);
    }
    private boolean dfs(TreeNode le, TreeNode ri) {
        if(le == null && ri == null) return  true;
        if(le == null || ri == null) return  false;
        return le.val == ri.val && isSymmetric(le) && isSymmetric(ri);
    }
}

20. 有效的括号 3

class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<Character>();
        for(int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            if(c=='(' || c=='[' || c=='{')
                stack.push(c);
            else{
                if(stack.isEmpty()){
                    return false;
                }
                char old = stack.pop();
                if(old=='(' && c == ')' || old=='['&& c == ']' || old=='{'&& c == '}'){
                    continue;
                }
                return false;
            } 
        }
        return stack.isEmpty();
    }
}

143. 重排链表 3

1.将链表分成两部分,后部分翻转,每部分都尾置0防止纠缠
2.奇数个节点是,前一段比后一段多一个

class Solution {
    public void reorderList(ListNode head) {
        if(head == null) return;
    //找到中点
        ListNode d = new ListNode(-1);
        d.next = head;
        ListNode res = d;
        ListNode f = head;
        ListNode s = head;
        while(f.next != null && f.next.next != null){
            f = f.next.next;
            s = s.next;
        }

        ListNode tail1 = s;
        s = s.next;
        tail1.next = null;
        ListNode pre = null;
        // 翻转后面的
        while(s != null){
            ListNode t = s.next;
            s.next = pre;
            pre = s;
            s = t;
        }
        
        while (head != null && pre != null){
            d.next = head;
            head = head.next;
            d = d.next;
            d.next = pre;
            pre = pre.next;
            d = d.next;
        }
        if(head != null){
            d.next = head;
        }
        head = res.next;
    }
}

54. 螺旋矩阵 2

这个算是比较清楚的,
当行或列是奇数时,后两个要判断是否重复

在这里插入代码片public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> list = new ArrayList<Integer>();
        if(matrix == null || matrix.length == 0)
    		return list;
        int m = matrix.length;
        int n = matrix[0].length;
        int i = 0; 

        //统计矩阵从外向内的层数,如果矩阵非空,那么它的层数至少为1层
        int count = (Math.min(m, n)+1)/2;
        //从外部向内部遍历,逐层打印数据
        while(i < count) {
        	for (int j = i; j < n-i; j++) {
				list.add(matrix[i][j]);
			}
        	for (int j = i+1; j < m-i; j++) {
				list.add(matrix[j][(n-1)-i]);
			}
        	
        	for (int j = (n-1)-(i+1); j >= i && (m-1-i != i); j--) {
				list.add(matrix[(m-1)-i][j]);
			}
        	for (int j = (m-1)-(i+1); j >= i+1 && (n-1-i) != i; j--) {
				list.add(matrix[j][i]);
			}
        	i++;
        }    
        return list;
    }

作者:liao-tian-yi-jian
链接:https://leetcode-cn.com/problems/spiral-matrix/solution/luo-xuan-ju-zhen-by-liao-tian-yi-jian/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

221. 最大正方形 2

dp[i][j]标识以i,j为右下角的最大的正方形的边长

class Solution {
    public int maximalSquare(char[][] matrix) {
        //动态规划:

        int maxLen = 0;
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return maxLen;
        }             
        int row = matrix.length;
        int col = matrix[0].length;
        int[][] dp = new int[row][col];
   
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                if (matrix[i][j] == '1'){
                    if(i == 0 || j == 0) dp[i][j] = 1;
                    else{
                        dp[i][j] = Math.min(Math.min(dp[i-1][j], dp[i][j-1]), dp[i-1][j-1])+1;                        
                    }
                    maxLen = Math.max(maxLen, dp[i][j]);
                }
            }
        }
        
        return maxLen * maxLen;
    }
}

23. 合并K个排序链表 2

只需要保证加的时候不为空即可,无需判断取的时候是否为空

class Solution {
      public ListNode mergeKLists(ListNode[] lists) {
            ListNode d = new ListNode(-1);
            ListNode res = d;
            Queue<ListNode> pq = new PriorityQueue<>((l1,l2)->l1.val-l2.val);
            for (int i = 0; i < lists.length; i++) {
                if(lists[i] != null)
                    pq.offer(lists[i]);
            }
            while(!pq.isEmpty()){
                  ListNode t =  pq.poll();
                  d.next = t;
                  d = t;
                  if(t.next != null){
                        pq.offer(t.next);
                  }
            }
            return res.next;
      }
}

83. 删除排序链表中的重复元素 2

class Solutison {
    public ListNode deleteDuplicates(ListNode head) {
        ListNode res = head;
        while(head != null && head.next != null){
            if(head.val == head.next.val){
                head.next = head.next.next;
            }else{
                head = head.next;
            }
        }
        return res;
    }
}

70. 爬楼梯 2

剑指 Offer 61. 扑克牌中的顺子 2

最大牌 - 最小牌 < 5 则可构成顺子

666啊。

class Solution {
    public boolean isStraight(int[] nums) {
        int joker = 0;
        Arrays.sort(nums); // 数组排序
        for(int i = 0; i < 4; i++) {
            if(nums[i] == 0) joker++; // 统计大小王数量
            else if(nums[i] == nums[i + 1]) return false; // 若有重复,提前返回 false
        }
        return nums[4] - nums[joker] < 5; // 最大牌 - 最小牌 < 5 则可构成顺子
    }
}

作者:jyd
链接:https://leetcode-cn.com/problems/bu-ke-pai-zhong-de-shun-zi-lcof/solution/mian-shi-ti-61-bu-ke-pai-zhong-de-shun-zi-ji-he-se/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

32. 最长有效括号 2

非常好的一个思路:

  • 在栈底放入-1这个边界
public class Solution {
    public int longestValidParentheses(String s) {
        int maxans = 0;
        Stack<Integer> stack = new Stack<>();
        stack.push(-1);
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.push(i);
            } else {
                stack.pop();
                if (stack.empty()) {
                    stack.push(i);//说明弹出前栈里只有一个值,除了)就是-1
                } else {
                    maxans = Math.max(maxans, i - stack.peek());//逐步尝试更新
                    
                }
            }
        }
        return maxans;
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-valid-parentheses/solution/zui-chang-you-xiao-gua-hao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

剑指 Offer 42. 连续子数组的最大和 2

class Solution {
    public int maxSubArray(int[] nums) {
        int res = nums[0];
        int pre = nums[0];
        for(int i = 1; i < nums.length; i++) {
            pre = nums[i] + Math.max(pre, 0);
            res = Math.max(res, pre);
        }
        return res;
    }
}

415. 字符串相加 2

要让我写,肯定要三个循环,类似两个链表合并那种。

有没有想起来寻找两个链表交点的那道题?也是直接一个循环,使用三目运算符无痛替换。

有时候有些题套路比思路重要

编程八股文奥利给!

class Solution {
    public String addStrings(String num1, String num2) {
        StringBuilder res = new StringBuilder("");
        int i = num1.length() - 1, j = num2.length() - 1, carry = 0;
        while(i >= 0 || j >= 0){
            int n1 = i >= 0 ? num1.charAt(i) - '0' : 0;
            int n2 = j >= 0 ? num2.charAt(j) - '0' : 0;
            int tmp = n1 + n2 + carry;
            carry = tmp / 10;
            res.append(tmp % 10);
            i--; j--;
        }
        if(carry == 1) res.append(1);
        return res.reverse().toString();
    }
}

作者:jyd
链接:https://leetcode-cn.com/problems/add-strings/solution/add-strings-shuang-zhi-zhen-fa-by-jyd/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

41. 缺失的第一个正数 2

class Solution {
public int firstMissingPositive(int[] nums) {
        int n = nums.length;
        for (int i = 0; i < n; i++) {
        	// 将某个元素i放到i-1位置去。
            // nums[i] == nums[nums[i] - 1] 
            while (nums[i] > 0 && nums[i] <= n && nums[i] != nums[nums[i] - 1]) {
                swap(nums, i, nums[i] - 1);
            }
        }
        for (int i = 0; i < n; i++) {
            if (nums[i] != i + 1) {
                return i + 1;
            }
        }

        return n + 1;
    }

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

704. 二分查找 2

我的二分模板全天下第一嘿嘿。

  • 两边闭
  • <
  • 查找左和右边界时中点分别靠左和右
  • 最后要判断
class Solution {
  public int search(int[] nums, int target) {
    int pivot, left = 0, right = nums.length - 1;
    while (left < right) {
      pivot = left + (right - left) / 2;
      if (nums[pivot] == target) return pivot;
      if (target < nums[pivot]) right = pivot - 1;
      else left = pivot + 1;
    }
    return nums[left] == target ? left : -1;
  }
}

958. 二叉树的完全性检验 2

思路太棒了,层序遍历,判断前一个是null而后一个不是null即可。

class Solution {
    public boolean isCompleteTree(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();
        TreeNode prev = root;
        queue.add(root);
        while (!queue.isEmpty()) {
            TreeNode node = queue.remove();
            if (prev == null && node != null)
                return false;
            if (node != null) {
                queue.add(node.left);
                queue.add(node.right);
            }
            prev = node;
        }
        return true;
    }
}

作者:yuanyb
链接:https://leetcode-cn.com/problems/check-completeness-of-a-binary-tree/solution/hen-jian-dan-de-si-lu-dai-ma-hen-jian-ji-by-yuanyb/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

后端 69. x 的平方根 2

注意不要用

mid * mid == x 这样的判断条件,容易溢出

我太喜欢我的二分模板了,想和它开房。

class Solution {
    public int mySqrt(int x) {    
        // 二分查找左边界
        int le = 1;        
        int ri = x;
        while (le < ri){
            int mid = (le + ri) / 2;
            if(mid == x / mid) return mid;
            else if(mid > x / mid) ri = mid;
            else le = mid + 1;
        }
        return  le * le == x ? le : le - 1;
    }
}

114. 二叉树展开为链表 2

class Solution {
    public void flatten(TreeNode root) {
        dfs(root);
    }
    // 返回值分别是两个链表的尾部节点。
    private TreeNode dfs(TreeNode root) {
        if (root == null) return root;
        TreeNode ltail = dfs(root.left);
        TreeNode rtail = dfs(root.right);
        if(ltail != null){
            ltail.right = root.right;
            root.right = root.left;
            root.left = null;
        }
        // 右侧子树的链表不空,返回这个
        if(rtail != null) return rtail;
        // 左侧子树的链表不空,返回这个
        if(ltail != null) return ltail;
        return root;
    }
}

这个思路非常好,使用共有节点。

class Solution {
    //先序遍历,原地展开
private TreeNode pre = null;

public void flatten(TreeNode root) {
    if (root == null)
        return;
    flatten(root.right);
    flatten(root.left);
    root.right = pre;
    root.left = null;
    pre = root;
}
}
<think>嗯,用户想要找关于华为OD模式的Python代码题目以及测试方法。首先,我需要回忆一下之前收集的相关资料。根据引用[1]和[2],华为OD的面试题通常涉及常见算法,比如快速排序、逆波兰表达式等。用户可能希望了解如何准备这类题目,包括常见的题型、解题技巧以及测试方法。 用户提到的是Python,所以需要针对Python语言的特点来回答。例如,Python在处理列表、字符串操作时比较方便,但要注意时间复杂度和空间复杂度。比如在逆波兰表达式的题目中,使用栈结构,Python中用列表模拟栈,这样效率比较高。 接下来,用户可能需要具体的解题步骤,比如如何分析问题、选择合适的数据结构、编写代码时的注意事项,比如边界条件、异常处理等。例如,在递归或分治算法中,基线条件的设置很重要,否则容易导致栈溢出或错误结果。 测试技巧方面,单元测试和边界测试是关键。华为OD的题目可能会考察各种边缘情况,比如空输入、极端值等。使用Python的unittest模块或者assert语句可以帮助验证代码的正确性。例如,测试快速排序时,需要测试空数组、已排序数组、逆序数组等情况,确保算法在各种情况下都能正确运行。 另外,用户可能对代码的时间复杂度和空间复杂度分析感兴趣。比如快速排序的平均时间复杂度是$O(n \log n)$,但最坏情况下是$O(n^2)$,这时候需要优化,比如随机选择基准元素。在Python中,列表推导式可以简化代码,但要注意不要影响可读性。 可能还需要提到代码的可读性和规范,比如变量命名、注释等,虽然华为OD可能更注重功能正确性,但清晰的代码结构有助于面试官理解和评分。 最后,根据引用资料,用户可能需要具体的例子,比如逆波兰表达式求值、快速排序的实现,以及如何测试这些代码。提供一些示例代码和测试用例会更有帮助,同时引用相关的资料来增强可信度。</think>### 华为OD Python代码准备指南 #### 一、常见题型及解题思路 华为OD代码题多聚焦于基础算法与数据结构,以下是高频题型分类: 1. **数组与字符串操作** - 例题:逆波兰表达式求值(引用[2]中的代码) - 关键技巧:使用栈结构处理运算符优先级,注意Python整数除法向零取整的特性 2. **排序与分治算法** - 例题:快速排序(引用[1]示例代码) - 优化方向:三数取中法选择基准元素,减少最坏时间复杂度$O(n^2)$ 3. **动态规划** - 典型题目:最长递增子序列、背包问题 - 代码要点:状态转移方程需用备忘录或DP数组实现 4. **树与图遍历** - 高频题:二叉树层序遍历、图的DFS/BFS - Python实现技巧:用deque实现高效队列操作 #### 二、代码测试方法 1. **单元测试框架** ```python import unittest class TestSolution(unittest.TestCase): def test_quick_sort(self): self.assertEqual(quick_sort([3,1,2]), [1,2,3]) self.assertEqual(quick_sort([]), []) # 空数组边界测试 ``` 2. **边界条件验证** - 空输入测试(如空数组、空字符串) - 极值测试(如最大整数、最小负数) - 重复元素测试(排序类题目) 3. **复杂度分析工具** - 使用`timeit`模块测量执行时间 ```python import timeit print(timeit.timeit(lambda: quick_sort([5]*1000), number=100)) ``` #### 三、面试实战技巧 1. **代码规范要点** - 变量命名使用蛇形命名法(如`max_length`) - 添加关键注释(如`# 处理负数除法特殊情况`) 2. **代码步骤** ``` 问题分析 → 伪代码设计 → 边界处理 → 代码实现 → 测试验证 ``` 3. **高频考点示例** **题目**:实现字符串压缩算法(如`aaabbbbcc` → `a3b4c2`) ```python def compress(s): if not s: return "" res, count = [], 1 for i in range(1, len(s)): if s[i] == s[i-1]: count +=1 else: res.append(f"{s[i-1]}{count if count>1 else ''}") count = 1 res.append(f"{s[-1]}{count if count>1 else ''}") return ''.join(res) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值