博客记录-day145-力扣+编程题

一、力扣

1、缺失的第一个正数

41. 缺失的第一个正数

java 复制代码
class Solution {
    public int firstMissingPositive(int[] nums) {
        int n=nums.length;
        for(int i=0;i<n;i++){
            if(nums[i]<=0){
                nums[i]=n+1;
            }
        }
        for(int i=0;i<n;i++){
            int target=Math.abs(nums[i]);
            if(target<=n){
                nums[target-1]=-Math.abs(nums[target-1]);
            }
        }
        for(int i=0;i<n;i++){
            if(nums[i]>0){
                return i+1;
            }
        }
        return n+1;
    }
}

2、最小覆盖子串

76. 最小覆盖子串

java 复制代码
class Solution {
    public String minWindow(String s, String t) {
        int[] target=new int[128];
        for(var e:t.toCharArray()){
            target[e]++;
        }
        int[] count=new int[128];
        int left=0,right=0;
        int n=s.length();
        int resleft=0,resright=Integer.MAX_VALUE/2;
        while(right<n){
            count[s.charAt(right)]++;
            while(check(count,target)){
                if(right-left<resright-resleft){
                    resright=right;
                    resleft=left;
                }
                count[s.charAt(left++)]--;
            }
            right++;
        }
        return resright==Integer.MAX_VALUE/2?"":s.substring(resleft,resright+1);
    }
    public boolean check(int[] count,int[] target){
        for(int i=0;i<128;i++){
            if(count[i]<target[i]){
                return false;
            }
        }
        return true;
    }
}

3、字符串相乘

43. 字符串相乘

java 复制代码
class Solution {
    public String multiply(String num1, String num2) {
        if (num1.equals("0") || num2.equals("0")) {
            return "0";
        }
        String ans = "0";
        int m = num1.length(), n = num2.length();
        for (int i = n - 1; i >= 0; i--) {
            StringBuffer curr = new StringBuffer();
            int add = 0;
            for (int j = n - 1; j > i; j--) {
                curr.append(0);
            }
            int y = num2.charAt(i) - '0';
            for (int j = m - 1; j >= 0; j--) {
                int x = num1.charAt(j) - '0';
                int product = x * y + add;
                curr.append(product % 10);
                add = product / 10;
            }
            if (add != 0) {
                curr.append(add);
            }
            ans = addStrings(ans, curr.reverse().toString());
        }
        return ans;
    }

    public String addStrings(String num1, String num2) {
        int i = num1.length() - 1, j = num2.length() - 1, add = 0;
        StringBuffer ans = new StringBuffer();
        while (i >= 0 || j >= 0 || add != 0) {
            int x = i >= 0 ? num1.charAt(i) - '0' : 0;
            int y = j >= 0 ? num2.charAt(j) - '0' : 0;
            int result = x + y + add;
            ans.append(result % 10);
            add = result / 10;
            i--;
            j--;
        }
        ans.reverse();
        return ans.toString();
    }
}

4、二叉搜索树中的插入操作

701. 二叉搜索树中的插入操作

迭代法:

java 复制代码
class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        TreeNode node = new TreeNode(val);
        if (root == null) {
            return node;
        }

        TreeNode cur = root;
        while (true) {
            if (cur.val > val) {
                if (cur.left == null) {
                    cur.left = node;
                    break;
                }
                cur = cur.left;
            } else {
                if (cur.right == null) {
                    cur.right = node;
                    break;
                } 
                cur = cur.right;
            }
        }
        return root;
    }
}

递归写法:

java 复制代码
class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
        if (root == null) {
            return new TreeNode(val);
        }
        if (root.val < val) {
            root.right = insertIntoBST(root.right, val);
        } else {
            root.left = insertIntoBST(root.left, val);
        }
        return root;
    }
}

5、删除二叉搜索树中的节点

450. 删除二叉搜索树中的节点

java 复制代码
class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
        // 1. 递归终止条件:当前节点为空,直接返回null
        if (root == null) return null;

        // 2. 查找待删除节点
        if (root.val == key) {
            // 情况1:左子树为空,直接返回右子树作为新的子树根
            if (root.left == null) return root.right;
            // 情况2:右子树为空,直接返回左子树作为新的子树根
            if (root.right == null) return root.left;
            
            // 情况3:左右子树均存在
            // 找到左子树中的最大节点(最右节点)
            TreeNode t = root.left;
            while (t.right != null) t = t.right;
            // 将原右子树挂到左子树最大节点的右子树
            t.right = root.right;
            // 返回左子树作为新的根节点
            return root.left;
            
        } else if (root.val < key) {
            // 递归在右子树中删除节点,并更新当前节点的右指针
            root.right = deleteNode(root.right, key);
        } else {
            // 递归在左子树中删除节点,并更新当前节点的左指针
            root.left = deleteNode(root.left, key);
        }
        
        // 返回处理后的当前节点(可能已被修改)
        return root;
    }
}

6、修剪二叉搜索树

669. 修剪二叉搜索树

java 复制代码
class Solution {
    public TreeNode trimBST(TreeNode root, int low, int high) {
        // 递归终止条件:当前节点为空,直接返回null
        if (root == null) return null;

        // 当前节点值小于下界:说明当前节点及其左子树都不符合要求
        // 根据BST性质,左子树所有节点值都更小,因此只需递归处理右子树
        if (root.val < low) {
            return trimBST(root.right, low, high);
        }
        // 当前节点值大于上界:说明当前节点及其右子树都不符合要求
        // 根据BST性质,右子树所有节点值都更大,因此只需递归处理左子树
        else if (root.val > high) {
            return trimBST(root.left, low, high);
        }

        // 当前节点值在范围内,递归修剪左右子树
        // 注意:需要将修剪后的子树重新赋值给当前节点的左右指针
        root.left = trimBST(root.left, low, high);   // 修剪左子树
        root.right = trimBST(root.right, low, high); // 修剪右子树

        // 返回当前已修剪的节点(作为父节点的子节点)
        return root;
    }
}

二、语雀-编程题

1、如何用队列实现一个栈?

✅如何用队列实现一个栈?

225. 用队列实现栈

  1. 将新元素添加到inque队尾
  2. 将outque中的全部元素依次转移到inque中
  3. 交换两个队列的引用,使得outque始终保存最新栈状态
java 复制代码
import java.util.ArrayDeque;

class MyStack {
    // 使用两个双端队列模拟栈的操作
    // inque 用于入栈时的临时存储
    // outque 用于出栈操作,保持栈顶元素在队首
    ArrayDeque<Integer> inque = new ArrayDeque<>();
    ArrayDeque<Integer> outque = new ArrayDeque<>();

    public MyStack() {
        // 构造函数无需特殊初始化
    }
    
    /**
     * 入栈操作
     * @param x 待压入栈的元素
     * 实现思路:
     * 1. 将新元素添加到inque队尾
     * 2. 将outque中的全部元素依次转移到inque中(反转原有顺序)
     * 3. 交换两个队列的引用,使得outque始终保存最新栈状态
     * 此操作确保新元素始终位于outque队首,符合栈的后进先出特性
     */
    public void push(int x) {
        inque.offerLast(x);          // 将新元素加入inque队尾
        while (!outque.isEmpty()) {  // 将outque现有元素全部转移到inque
            inque.offer(outque.poll());
        }
        // 交换队列引用,使outque始终持有当前栈内容
        ArrayDeque<Integer> temp = inque;
        inque = outque;
        outque = temp;
    }
    
    /** 弹出栈顶元素 */
    public int pop() {
        return outque.poll();  // 直接移除并返回outque队首元素(即栈顶)
    }
    
    /** 获取栈顶元素但不弹出 */
    public int top() {
        return outque.peek();       // 查看outque队首元素
    }
    
    /** 判断栈是否为空 */
    public boolean empty() {
        return inque.isEmpty() && outque.isEmpty();  // 两队列均为空时栈为空
    }
}

2、如何用栈实现一个队列

✅如何用栈实现一个队列?

232. 用栈实现队列

将一个栈当作输入栈,用于压入 push 传入的数据;另一个栈当作输出栈,用于 pop 和 peek 操作。

每次 pop 或 peek 时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。

java 复制代码
class MyQueue {
    ArrayDeque<Integer> stack1=new ArrayDeque<>();
    ArrayDeque<Integer> stack2=new ArrayDeque<>();
    public MyQueue() {
        
    }
    
    public void push(int x) {
        stack1.push(x);

    }
    
    public int pop() {
        if(stack2.isEmpty()){
            while(!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }
    
    public int peek() {
        if(stack2.isEmpty()){
            while(!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.peek();
    }
    
    public boolean empty() {
        return stack1.isEmpty()&&stack2.isEmpty();
    }
}

3、快速排序

912. 排序数组

java 复制代码
class Solution {
    Random random=new Random();
    public int[] sortArray(int[] nums) {
        quicksort(nums,0,nums.length-1);
        return nums;
    }
    public void quicksort(int[] nums,int left,int right){
        if(left>right) return;
        int partiton=left+random.nextInt(right-left+1);
        swap(nums,partiton,left);
        int i=left+1,j=right;
        while(true){
            while(i<=j&&nums[i]<nums[left]) i++;
            while(i<=j&&nums[j]>nums[left]) j--;
            if(i>=j) break;
            swap(nums,i,j);
            i++;
            j--;
        }
        swap(nums,left,j);
        quicksort(nums,left,j-1);
        quicksort(nums,j+1,right);
    }
    public void swap(int[] nums,int left,int right){
        int temp=nums[left];
        nums[left]=nums[right];
        nums[right]=temp;
    }
}

4、有一个包含N个整数的数组,请编写一个算法,找到其中的两个元素,使它们之差最小。时间复杂度必须为O(n)。

✅有一个包含N个整数的数组,请编写一个算法,找到其中的两个元素,使它们之差最小。时间复杂度必须为O(n)。

  • 该算法时间复杂度为O(n + k)(k为数值范围),适用于整数数组且数值范围可控的场景
  • 当前桶宽度设置为1(每个桶对应一个具体数值),可根据实际需求调整桶宽以优化性能

在元素均匀分布且桶内元素数量较小时,时间复杂度接近线性;否则可能退化为O(n log n)

java 复制代码
import java.util.Arrays;

public class MinDiff {

    public static void main(String[] args) {
        int[] arr = {3, 1, 4, 5, 9, 2, 6, 8, 7};
        int minDiff = findMinDiff(arr);
        System.out.println("最小差为:" + minDiff);
    }

    public static int findMinDiff(int[] arr) {
        int n = arr.length;
        if (n < 2) {
            return -1; // 数组元素不足,无法计算差值
        }

        // 步骤1:查找数组中的最小值和最大值
        int minVal = Integer.MAX_VALUE;
        int maxVal = Integer.MIN_VALUE;
        for (int i = 0; i < n; i++) {
            minval=Math.min(minVal,arr[i]);
            maxval=Math.max(maxVal,arr[i]);
        }

        // 步骤2:初始化桶结构
        int bucketCount = maxVal - minVal + 1; // 桶的数量等于数值范围的大小
        int[][] buckets = new int[bucketCount][n]; // 存储各桶元素
        int[] bucketSizes = new int[bucketCount]; // 记录各桶实际元素个数

        // 步骤3:将元素分配到对应的桶中
        for (int i = 0; i < n; i++) {
            int index = arr[i] - minVal; // 计算元素所属桶的索引
            buckets[index][bucketSizes[index]++] = arr[i]; // 将元素放入桶中
        }

        // 步骤4:对每个非空桶进行排序
        for (int i = 0; i < bucketCount; i++) {
            if (bucketSizes[i] > 0) {
                // 仅对桶内实际存在的元素进行排序
                Arrays.sort(buckets[i], 0, bucketSizes[i]);
            }
        }

        // 步骤5:计算相邻非空桶之间的最小差值
        int minDiff = Integer.MAX_VALUE;
        int prevMax = buckets[0][bucketSizes[0] - 1]; // 初始化为第一个桶的最大值(已排序)
        
        for (int i = 1; i < bucketCount; i++) {
            if (bucketSizes[i] == 0) {
                continue; // 跳过空桶
            }
            
            int currMin = buckets[i][0]; // 当前桶的最小值(已排序)
            int diff = currMin - prevMax; // 计算相邻桶差值
            
            if (diff < minDiff) {
                minDiff = diff; // 更新最小差值
            }
            
            prevMax = buckets[i][bucketSizes[i] - 1]; // 更新prevMax为当前桶的最大值
        }

        return minDiff;
    }
}

5、实现一个LRU缓存淘汰策略,支持get和put操作

✅实现一个LRU缓存淘汰策略,支持get和put操作

146. LRU 缓存

java 复制代码
class LRUCache {
    class ListNode{
        int key,val;
        ListNode prev,next;
        public ListNode(){};
        public ListNode(int key,int val){
            this.key=key;
            this.val=val;
        }
    }
    ListNode dummy;
    Map<Integer,ListNode> map;
    int capacity;
    public LRUCache(int capacity) {
        this.capacity=capacity;
        dummy=new ListNode();
        dummy.next=dummy;
        dummy.prev=dummy;
        map=new HashMap<>();
    }
    
    public int get(int key) {
        if(map.containsKey(key)){
            ListNode target=map.get(key);
            remove(target);
            pushFirst(target);
            return target.val;
        }else{
            return -1;
        }
    }
    
    public void put(int key, int value) {
        if(map.containsKey(key)){
            ListNode target=map.get(key);
            target.val=value;
            remove(target);
            pushFirst(target);
        }else{
            ListNode target=new ListNode(key,value);
            map.put(key,target);
            pushFirst(target);
            if(map.size()>capacity){
                ListNode last=dummy.prev;
                remove(last);
                map.remove(last.key);
            }
        }
    }
    public void remove(ListNode target){
        target.prev.next=target.next;
        target.next.prev=target.prev;
    }
    public void pushFirst(ListNode target){
        dummy.next.prev=target;
        target.next=dummy.next;
        target.prev=dummy;
        dummy.next=target;
    }
}

6、判断101-200之间有多少个质数,并输出所有质数

✅判断101-200之间有多少个质数,并输出所有质数

java 复制代码
public class PrimeNumbers {

    public static void main(String[] args) {
        int count = 0; // 统计质数的数量

        for (int i = 101; i <= 200; i++) {
            if (isPrime(i)) {
                System.out.println(i); // 输出质数
                count++;
            }
        }

        System.out.println("Total prime numbers between 101 and 200: " + count);
    }
    
    public static boolean isPrime(int n) {
        // 处理小于等于1的非质数情况
        if (n <= 1) {
            return false;
        }

        // 检查从2到n的平方根是否存在因子
        for (int i = 2; i <= Math.sqrt(n); i++) {
            if (n % i == 0) {
                return false; // 发现因子,非质数
            }
        }

        // 无因子,确认是质数
        return true;
    }
}

7、请分别写出一个Java堆、栈、元空间溢出的代码

✅请分别写出一个Java堆、栈、元空间溢出的代码

1. Java堆溢出

java 复制代码
import java.util.ArrayList;
import java.util.List;

public class HeapOverflow {

    public static void main(String[] args) {
        List<Object> objects = new ArrayList<>();
        while (true) {
            objects.add(new Object()); // 不断创建对象并保留引用
        }
    }

}

2. Java 栈溢出

java 复制代码
public class StackOverflow {

    public static void main(String[] args) {
        recursiveMethod(1); // 递归调用,没有终止条件
    }

    private static void recursiveMethod(int i) {
        recursiveMethod(i);
    }

}

3. 元空间溢出

java 复制代码
import javassist.ClassPool;

public class MetaspaceOverflow {

    public static void main(String[] args) {
        ClassPool classPool = ClassPool.getDefault();
        for (int i = 0; ; i++) {
            classPool.makeClass("Class" + i).toClass(); // 动态创建大量的类
        }
    }

}

8、给定一个二叉搜索树,请找出其中第k小的元素

✅给定一个二叉搜索树,请找出其中第k小的元素

java 复制代码
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

public class Solution {
    private int count = 0; // 用于计数已遍历的节点
    private int result = Integer.MIN_VALUE; // 存储第k小的元素

    public int kthSmallest(TreeNode root, int k) {
        inOrderTraverse(root, k);
        return result;
    }

    private void inOrderTraverse(TreeNode node, int k) {
        if (node == null) return;

        // 先遍历左子树
        inOrderTraverse(node.left, k);

        // 访问节点
        count++;
        if (count == k) {
            result = node.val;
            return; // 找到第k小的元素后返回
        }

        // 遍历右子树
        inOrderTraverse(node.right, k);
    }
}

9、两个线程,一个打印奇数,一个打印偶数,然后顺序打印出1-100

✅两个线程,一个打印奇数,一个打印偶数,然后顺序打印出1-100

java 复制代码
public class AlternatePrinting {
    private static int count = 1;
    private static final Object lock = new Object();

    public static void main(String[] args) {
        // 线程A负责打印奇数
        Thread threadA = new Thread(() -> {
            while (count <= 100) {
                synchronized (lock) {
                    if (count % 2 == 1) { // 打印奇数
                        System.out.println(Thread.currentThread().getName() + ": " + count++);
                        lock.notify(); // 唤醒线程B
                    } else {
                        try {
                            lock.wait(); // 让出锁并等待
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }, "Thread-A");

        // 线程B负责打印偶数
        Thread threadB = new Thread(() -> {
            while (count <= 100) {
                synchronized (lock) {
                    if (count % 2 == 0) { // 打印偶数
                        System.out.println(Thread.currentThread().getName() + ": " + count++);
                        lock.notify(); // 唤醒线程A
                    } else {
                        try {
                            lock.wait(); // 让出锁并等待
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }, "Thread-B");

        threadA.start();
        threadB.start();
    }
}

10、两个线程,一个打印123,一个打印ABC,交替输出1A2B3C

✅两个线程,一个打印123,一个打印ABC,交替输出1A2B3C

java 复制代码
public class PrintingWithWaitNotify {
    private static final Object lock = new Object();
    private static boolean printNumber = true;

    public static void main(String[] args) {
        Thread numberThread = new Thread(new NumberPrinter());
        Thread letterThread = new Thread(new LetterPrinter());

        numberThread.start();
        letterThread.start();
    }

    static class NumberPrinter implements Runnable {
        @Override
        public void run() {
            synchronized (lock) {
                try {
                    for (int i = 1; i <= 3; i++) {
                        while (!printNumber) {
                            lock.wait();
                        }
                        System.out.print(i);
                        printNumber = false;
                        lock.notify();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    static class LetterPrinter implements Runnable {
        @Override
        public void run() {
            synchronized (lock) {
                try {
                    for (char c = 'A'; c <= 'C'; c++) {
                        while (printNumber) {
                            lock.wait();
                        }
                        System.out.print(c);
                        printNumber = true;
                        lock.notify();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

11、10个线程模拟赛马,所有马就绪后才能开跑,所有马到达终点后裁判宣布赛马成绩

✅10个线程模拟赛马,所有马就绪后才能开跑,所有马到达终点后裁判宣布赛马成绩

要实现这个功能,可以使用 CountDownLatch 来确保所有马都就绪后再开始比赛,并使用 CyclicBarrier 来确保所有马到达终点后裁判再宣布成绩。

java 复制代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

public class HorseRace {
    // 用于存储赛马成绩
    private static List<String> results = Collections.synchronizedList(new ArrayList<>());

    // 用于控制所有马同时开跑
    private static CountDownLatch startLatch = new CountDownLatch(1);

    // 用于确保所有马到达终点后再宣布成绩
    private static CyclicBarrier finishBarrier = new CyclicBarrier(10, new Runnable() {
        @Override
        public void run() {
            // 裁判宣布成绩
            System.out.println("Race finished! Announcing results:");
            for (String result : results) {
                System.out.println(result);
            }
        }
    });

    public static void main(String[] args) {
        for (int i = 1; i <= 10; i++) {
            new Thread(new Horse("Horse " + i)).start();
        }

        // 所有马就绪后开跑
        try {
            System.out.println("All horses ready. Race starts now!");
            startLatch.countDown(); // 马开跑
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    static class Horse implements Runnable {
        private String name;

        public Horse(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            try {
                // 马就绪,等待开跑信号
                startLatch.await();

                // 马开始跑
                long raceTime = (long) (Math.random() * 10000); // 模拟跑的时间
                Thread.sleep(raceTime);

                // 马到达终点
                results.add(name + " finished in " + raceTime + " ms");

                // 等待其他马到达终点
                finishBarrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

12、线程池中怎么设置超时时间?一个线程如果要运行10s,怎么在1s就抛出异常

✅线程池中怎么设置超时时间?一个线程如果要运行10s,怎么在1s就抛出异常

java 复制代码
import java.util.concurrent.*;

public class ThreadPoolTimeoutExample {

    public static void main(String[] args) {
        // 创建一个线程池
        ExecutorService executor = Executors.newFixedThreadPool(2);

        // 创建一个Callable任务
        Callable<String> task = () -> {
            // 模拟执行10秒的任务
            Thread.sleep(10000);
            return "Task completed";
        };

        // 提交任务并获取Future对象
        Future<String> future = executor.submit(task);

        try {
            // 设置任务的超时时间为1秒
            String result = future.get(1, TimeUnit.SECONDS);  // 1秒超时
            System.out.println(result);
        } catch (TimeoutException e) {
            System.out.println("Task timed out!");
            future.cancel(true); // 取消任务
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        } finally {
            executor.shutdown();
        }
    }
}
相关推荐
uhakadotcom11 小时前
完了,AI中台比数据中台更短命
面试·架构·github
刃神太酷啦14 小时前
聚焦 string:C++ 文本处理的核心利器--《Hello C++ Wrold!》(10)--(C/C++)
java·c语言·c++·qt·算法·leetcode·github
饼干哥哥15 小时前
数据安全无小事,用Github免费定时备份n8n工作流
github
掘金安东尼16 小时前
7个【宝藏工具】从智能画图到 SSL 自动化,一应俱全
前端·面试·github
HelloGitHub16 小时前
一周 Star 破万的开源项目「GitHub 热点速览」
开源·github
qianmoQ1 天前
GitHub 趋势日报 (2025年06月14日)
github
梓羽玩Python2 天前
12K+ Star的离线语音神器!50MB模型秒杀云端API,隐私零成本,20+语种支持!
人工智能·python·github
掘金安东尼2 天前
9 个【宝藏工具】精选,大幅提升效率与灵感!
前端·面试·github
kymjs张涛2 天前
前沿技术周刊 2025-06-16
前端·ios·github
独立开阀者_FwtCoder2 天前
《独立开发工具 • 半月刊》 第 012 期
前端·javascript·github