From 0760f5b78c63b6ec3eb6ee73bca0bcd056ec523d Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Fri, 23 May 2025 09:17:44 +0800 Subject: [PATCH] =?UTF-8?q?5.23=20=E4=BD=8D=E8=BF=90=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/bitwise/AddBinary.java | 35 +++++++++ src/main/java/bitwise/HammingWeight.java | 24 ++++++ src/main/java/bitwise/RangeBitwiseAnd.java | 37 +++++++++ src/main/java/bitwise/ReverseBits.java | 45 +++++++++++ .../java/{trick => bitwise}/SingleNumber.java | 2 +- src/main/java/bitwise/SingleNumber2.java | 50 +++++++++++++ src/main/java/heap/KSmallestPairs.java | 75 +++++++++++++++++++ 7 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 src/main/java/bitwise/AddBinary.java create mode 100644 src/main/java/bitwise/HammingWeight.java create mode 100644 src/main/java/bitwise/RangeBitwiseAnd.java create mode 100644 src/main/java/bitwise/ReverseBits.java rename src/main/java/{trick => bitwise}/SingleNumber.java (98%) create mode 100644 src/main/java/bitwise/SingleNumber2.java create mode 100644 src/main/java/heap/KSmallestPairs.java diff --git a/src/main/java/bitwise/AddBinary.java b/src/main/java/bitwise/AddBinary.java new file mode 100644 index 0000000..0465a15 --- /dev/null +++ b/src/main/java/bitwise/AddBinary.java @@ -0,0 +1,35 @@ +package bitwise; +/** + * 题目: 67. 二进制求和 (addBinary) + * 描述:给你两个二进制字符串 a 和 b ,以二进制字符串的形式返回它们的和。 + * + * 示例 1: + 输入:a = "11", b = "1" + 输出:"100" + + * 链接:https://leetcode.cn/problems/add-binary/ + */ +public class AddBinary { + public String addBinary(String a, String b) { + int len1=a.length(),len2=b.length(); + int done=0; + int carry=0; + int cura,curb; + StringBuilder sb=new StringBuilder(); + while (done>= 1; + right >>= 1; + shift++; + } + // 把对齐后的公共前缀左移回去,低位补 0 + return left << shift; + } +} diff --git a/src/main/java/bitwise/ReverseBits.java b/src/main/java/bitwise/ReverseBits.java new file mode 100644 index 0000000..6faac0c --- /dev/null +++ b/src/main/java/bitwise/ReverseBits.java @@ -0,0 +1,45 @@ +package bitwise; +/** + * 题目: 190. 颠倒二进制位 (addBinary) + * 描述:颠倒给定的 32 位无符号整数的二进制位。 + * + * 提示: + * + * 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。 + * 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在 示例 2 中,输入表示有符号整数 -3,输出表示有符号整数 -1073741825。 + * + * 示例 1: + 输入:n = 00000010100101000001111010011100 + 输出:964176192 (00111001011110000010100101000000) + 解释:输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596, + 因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。 + + * 链接:https://leetcode.cn/problems/reverse-bits/ + */ +public class ReverseBits { + /** + * 逐位提取+拼装 + * + * 初始化一个结果变量 res = 0。 + * 对于原数 n 的每一位(共 32 位),从最低位到最高位做: + * 先把 res 左移 1 位,为下一个要写入的位置腾出最低位。 + * 从 n 中取出当前的最低位 n & 1,把它或进 res。 + * 再把 n 无符号右移 1 位(>>>= 1),为下一轮提取准备。 + * 重复 32 次,最后 res 就是把原来 n 的二进制“倒过来”的结果。 + * @param n + * @return + */ + public int reverseBits(int n) { + int res = 0; + // 共处理 32 位 + for (int i = 0; i < 32; i++) { + // 先把 res 左移,为下一位腾出最低位 + res <<= 1; + // 取出 n 的最低位,或进 res 的最低位 + res |= (n & 1); + // 无符号右移 n,推动下一位到最低位 + n >>>= 1; + } + return res; + } +} diff --git a/src/main/java/trick/SingleNumber.java b/src/main/java/bitwise/SingleNumber.java similarity index 98% rename from src/main/java/trick/SingleNumber.java rename to src/main/java/bitwise/SingleNumber.java index 97d6aa7..7937c6e 100644 --- a/src/main/java/trick/SingleNumber.java +++ b/src/main/java/bitwise/SingleNumber.java @@ -1,4 +1,4 @@ -package trick; +package bitwise; import java.util.HashSet; diff --git a/src/main/java/bitwise/SingleNumber2.java b/src/main/java/bitwise/SingleNumber2.java new file mode 100644 index 0000000..b8fbabb --- /dev/null +++ b/src/main/java/bitwise/SingleNumber2.java @@ -0,0 +1,50 @@ +package bitwise; +/** + * 题目: 137. 只出现一次的数字 II (singleNumber) + * 描述:给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。 + * + * 你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。 + * + 示例 1: + 输入:nums = [2,2,3,2] + 输出:3 + + * 链接:https://leetcode.cn/problems/single-number-ii/ + */ +//不会 +public class SingleNumber2 { + /** + * 除了那唯一一个只出现一次的数,数组里其它每个数都出现了三次。把它们在二进制层面“叠加”起来,出现三次的数的每一位(0/1) + * 在总和里都会是 0×3=0 或 1×3=3,而那个只出现一次的数的每一位则只加 0×1=0 或 1×1=1。于是: + * + * 统计所有数在第 i 位上 1 的个数,记作 count[i]。 + * count[i] % 3 要么是 0(说明那一位上只来自出现三次部分),要么是 1(说明唯一数在这一位上是 1)。 + * 把所有 count[i] % 3 按位重组,就得到了那个只出现一次的整数的二进制形式。 + * @param nums + * @return + */ + public int singleNumber(int[] nums) { + // 用于统计 nums 中每一位上 1 出现的次数 + int[] bitCount = new int[32]; + + // 累加所有数字的二进制位 + for (int num : nums) { + for (int i = 0; i < 32; i++) { + // 提取 num 的第 i 位:(num >>> i) & 1 + bitCount[i] += (num >>> i) & 1; + } + } + + // 重组只出现一次的那个数 + int result = 0; + for (int i = 0; i < 32; i++) { + // 如果 bitCount[i] % 3 == 1,说明唯一数的第 i 位为 1 + if (bitCount[i] % 3 != 0) { + // 将第 i 位置为 1 + result |= (1 << i); + } + } + + return result; + } +} diff --git a/src/main/java/heap/KSmallestPairs.java b/src/main/java/heap/KSmallestPairs.java new file mode 100644 index 0000000..42837a8 --- /dev/null +++ b/src/main/java/heap/KSmallestPairs.java @@ -0,0 +1,75 @@ +package heap; + +import java.util.ArrayList; +import java.util.List; +import java.util.PriorityQueue; + +/** + * 题目: 373. 查找和最小的 K 对数字 (kSmallestPairs) + * 描述:给定两个以 非递减顺序排列 的整数数组 nums1 和 nums2 , 以及一个整数 k 。 + * 定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2 。 + * 请找到和最小的 k 个数对 (u1,v1), (u2,v2) ... (uk,vk) 。 + * + * 示例 1: + 输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3 + 输出: [1,2],[1,4],[1,6] + 解释: 返回序列中的前 3 对数: + [1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6] + + * 链接:https://leetcode.cn/problems/find-k-pairs-with-smallest-sums/ + */ +//有思路 但是超出时间限制,需要优化 +public class KSmallestPairs { + /** + * 可以把所有可能的组合看作一个虚拟的二维矩阵: + * + * 行代表 nums1[i] + * 列代表 nums2[j] + * 每个点 (i,j) 对应的值是 nums1[i] + nums2[j] + * 这个矩阵的特点是:从左到右、从上到下递增,因为两个数组都升序。 + * + * 我们不需要全部生成矩阵,而是只维护当前“最小的候选对”,类似 Dijkstra 算法或 BFS: + * + * 初始时,把前 k 行的第一列(即 (nums1[i], nums2[0]))放入堆中。因为后面的列比前面的大,我们先选列头。 + * 每次弹出堆顶(最小的和),把它加入结果列表。 + * 如果该对还有下一列(即 (i, j+1) 存在),就把 (i, j+1) 加入堆,作为下一个候选。 + * 这样我们始终只关注当前最小的组合,最多进行 k 次堆操作,高效。 + * @param nums1 + * @param nums2 + * @param k + * @return + */ + public List> kSmallestPairs(int[] nums1, int[] nums2, int k) { + List> res = new ArrayList<>(); + + // 边界处理:任一数组为空 或 k==0,直接返回空结果 + if (nums1.length == 0 || nums2.length == 0 || k == 0) return res; + + // 小顶堆,存储的是每对数的索引 [i, j],按对应的和升序排列 + PriorityQueue minHeap = new PriorityQueue<>( + (a, b) -> nums1[a[0]] + nums2[a[1]] - nums1[b[0]] - nums2[b[1]] + ); + + // 初始化:将 nums1 的前 k 个元素与 nums2[0] 组成的数对放入堆中 + // 因为只推进列,所以只需要每一行的第一个元素 + for (int i = 0; i < Math.min(nums1.length, k); i++) { + minHeap.offer(new int[]{i, 0}); // i 表示 nums1 的索引,j=0 是固定的起点 + } + + // 取出堆顶最小的数对,直到取满 k 个或者堆空为止 + while (k-- > 0 && !minHeap.isEmpty()) { + int[] pos = minHeap.poll(); // 当前最小的数对在 nums1[pos[0]], nums2[pos[1]] + int i = pos[0], j = pos[1]; + + // 把数对值加入结果集 + res.add(List.of(nums1[i], nums2[j])); + + // 如果当前数对还有下一列,就推进下一列(仍然在第 i 行) + if (j + 1 < nums2.length) { + minHeap.offer(new int[]{i, j + 1}); + } + } + + return res; + } +}