日拱一卒


1 一周见闻

1.1 技术文章

1.2 泛互联网文章

2 技术总结

3 Algorithm(算法题)

class Solution {
    public int countPrimes(int n) {
        boolean[] isPrime = new boolean[n];
        Arrays.fill(isPrime, true);
        for(int i = 2; i * i < n; i++) {
            if(isPrime[i]) {
                for(int j = i * i; j < n; j += i) {
                    isPrime[j] = false;
                }
            }
        }
        int count = 0;
        for(int i = 2; i < n; i++) {
            if(isPrime[i]) {
                count++;
            }
        }
        return count;
    }
}


//leetcode submit region begin(Prohibit modification and deletion)
class Solution {

    /**
     * 丑数 就是只包含质因数 2、3 和 5 的正整数。
     *
     * 给你一个整数 n ,请你判断 n 是否为 丑数 。如果是,返回 true ;否则,返回 false 。
     *
     * 示例 1:
     *
     * 输入:n = 6
     * 输出:true
     * 解释:6 = 2 × 3
     * 示例 2:
     *
     * 输入:n = 1
     * 输出:true
     * 解释:1 没有质因数,因此它的全部质因数是 {2, 3, 5} 的空集。习惯上将其视作第一个丑数。
     * 示例 3:
     *
     * 输入:n = 14
     * 输出:false
     * 解释:14 不是丑数,因为它包含了另外一个质因数 7 。
     * 提示:
     *
     * -231 <= n <= 231 - 1
     * @param n
     * @return
     */
    public boolean isUgly(int n) {
        if(n <= 0) {
            return false;
        }

        while(n % 2 == 0) {
            n /= 2;
        }

        while(n % 3 == 0) {
            n /= 3;
        }

        while(n % 5 == 0) {
            n /= 5;
        }
        return n == 1;
    }
}
//leetcode submit region end(Prohibit modification and deletion)
class Solution {
    public int nthUglyNumber(int n) {
        int i = 1;
        int[] ugly = new int[n + 1];
        int p1 = 1;
        int p2 = 1;
        int p3 = 1;
        int step2 = 1;
        int step3 = 1;
        int step5 = 1;

        while(i <= n) {
            int min = Math.min(Math.min(step2, step3), step5);
            ugly[i] = min;
            i++;
            if(min == step2) {
                step2 =  2 * ugly[p1++];
            }
            if(min == step3) {
                step3 = 3 * ugly[p2++];
            }
            if(min == step5) {
                step5 = 5 * ugly[p3++];
            }
        }
        return ugly[n];
    }
}
class Solution {
    /**
     * 给你一个 n x n 矩阵 matrix ,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
     * 请注意,它是 排序后 的第 k 小元素,而不是第 k 个 不同 的元素。
     *
     * 你必须找到一个内存复杂度优于 O(n2) 的解决方案。
     *
     * 示例 1:
     *
     * 输入:matrix = [[1,5,9],[10,11,13],[12,13,15]], k = 8
     * 输出:13
     * 解释:矩阵中的元素为 [1,5,9,10,11,12,13,13,15],第 8 小元素是 13
     * 示例 2:
     *
     * 输入:matrix = [[-5]], k = 1
     * 输出:-5
     * 提示:
     *
     * n == matrix.length
     * n == matrix[i].length
     * 1 <= n <= 300
     * -109 <= matrix[i][j] <= 109
     * 题目数据 保证 matrix 中的所有行和列都按 非递减顺序 排列
     * 1 <= k <= n2
     * 进阶:
     *
     * 你能否用一个恒定的内存(即 O(1) 内存复杂度)来解决这个问题?
     * 你能在 O(n) 的时间复杂度下解决这个问题吗?这个方法对于面试来说可能太超前了,但是你会发现阅读这篇文章( this paper )很有趣。
     * @param matrix
     * @param k
     * @return
     */
    public int kthSmallest(int[][] matrix, int k) {
        PriorityQueue<int[]> q = new PriorityQueue<>((a,b) -> {
            return a[0] - b[0];
        });
        int n = matrix.length;
        for(int i = 0; i < n; i++) {
            q.offer(new int[] {matrix[i][0], i, 0});
        }

        int res = 0;
        while(!q.isEmpty() && k > 0) {
            int[] cur = q.poll();
            int i = cur[1];
            int j = cur[2];
            k--;
            res = cur[0];
            if(j + 1 < n) {
                q.offer(new int[]{matrix[i][j + 1], i, j + 1});
            }
        }
        return res;
    }
}

//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public int maximumPrimeDifference(int[] nums) {
        int p1 = -1; // 初始化第一个质数的下标
        int p2 = -1; // 初始化最后一个质数的下标
        for(int i = 0; i < nums.length; i++) {
            if(isPrime(nums[i])) {
                if(p1 == -1) {
                    p1 = i;
                }
                p2 = i;
            }
        }
        return p2 - p1;
    }

    public boolean isPrime(int num) {
        if (num < 2) return false; // 小于2的数不是质数
        // num 题设限制大于 0
        for(int i = 2; i * i <= num; i++) {
            if(num % i == 0) {
                return false;
            }
        }
        return true;
    }
}
//leetcode submit region end(Prohibit modification and deletion)

class Solution {
    public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        PriorityQueue<int[]> q = new PriorityQueue<>((a, b) -> {
            return a[0] + a[1] - b[0] - b[1];
        });

        for(int i = 0; i < nums1.length; i++) {
            q.offer(new int[]{nums1[i], nums2[0], 0});
        }

        List<List<Integer>> res = new ArrayList<>();
        while(!q.isEmpty() && k > 0) {
            int[] cur = q.poll();
            res.add(Arrays.asList(cur[0], cur[1]));
            if(cur[2] + 1 < nums2.length) {
                q.offer(new int[]{cur[0], nums2[cur[2] + 1], cur[2] + 1});
            }
            k--;
        }
        return res;

    }
}

//leetcode submit region begin(Prohibit modification and deletion)
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null) {
            return head;
        }
        ListNode last = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return last;
    }
}
//leetcode submit region end(Prohibit modification and deletion)


//leetcode submit region begin(Prohibit modification and deletion)
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    /**
     * 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。
     *
     * 示例 1:
     *
     *
     * 输入:head = [1,2,3,4,5], left = 2, right = 4
     * 输出:[1,4,3,2,5]
     * 示例 2:
     *
     * 输入:head = [5], left = 1, right = 1
     * 输出:[5]
     * 提示:
     *
     * 链表中节点数目为 n
     * 1 <= n <= 500
     * -500 <= Node.val <= 500
     * 1 <= left <= right <= n
     * 进阶: 你可以使用一趟扫描完成反转吗?
     * @param head
     * @param left
     * @param right
     * @return
     */



    public ListNode reverseBetween(ListNode head, int left, int right) {
        if(left == 1) {
            return reverseN(head, right);
        }
        head.next = reverseBetween(head.next, left - 1, right - 1);
        return head;
    }

    ListNode successor = null; // 后驱节点
    // 反转以 head 为起点的 n 个节点,返回新的头结点
    // 1 2 3, n = 2 -> 2 1 3
    public ListNode reverseN(ListNode head, int n) {
        if (n == 1) {
            // 记录第 n + 1 个节点
            successor = head.next;
            return head;
        }
        // 以 head.next 为起点,需要反转前 n - 1 个节点
        ListNode last = reverseN(head.next, n - 1);

        head.next.next = head;
        // 让反转之后的 head 节点和后面的节点连起来
        head.next = successor;
        return last;

    }
}
//leetcode submit region end(Prohibit modification and deletion)
 

//leetcode submit region begin(Prohibit modification and deletion)
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    // 快慢指针找到要反转的起始节点
    // 翻转后半部分
    // 遍历对比
    public boolean isPalindrome(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        if(fast != null) {
            slow = slow.next;
        }
        ListNode last = reverse(slow);


        while(last != null) {
            if(last.val != head.val) {
                return false;
            }
            last = last.next;
            head = head.next;
        }
        return true;

    }

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



}
//leetcode submit region end(Prohibit modification and deletion)

class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head == null) {
            return head;
        }

        ListNode a = head;
        ListNode b = head;

        // 12345
        for(int i = 0; i < k; i++) {
            if(b == null) {
                return head;
            }
            b = b.next;
        }

        ListNode newHead = reverse(a, b);
        a.next = reverseKGroup(b, k);
        return newHead;
    }

    public ListNode reverse(ListNode a, ListNode b) {
        ListNode pre = null;
        ListNode cur = a;

        while(cur != b) {
            ListNode next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }


}



//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int p1 = m - 1;
        int p2 = n - 1;
        int i = m + n - 1;
        while(p1 >= 0 && p2 >= 0) {
            if(nums1[p1] > nums2[p2]) {
                nums1[i--] = nums1[p1--];
            } else {
                nums1[i--] = nums2[p2--];
            }
        }

        while (p2 >= 0) {
            nums1[i--] = nums2[p2--];
        }
    }
}
//leetcode submit region end(Prohibit modification and deletion)