只出现一次的数字
题目
思路
这题很有意思,考察的知识点也比较偏,涉及到位运算。
由于每个元素除了一个只出现一次外,其他元素都出现了两次,所以我们可以利用位运算中的异或操作来解决这个问题。
位运算(异或操作):
- 异或操作(
^
)的性质:x ^ x = 0
(任何数与自身异或为 0)x ^ 0 = x
(任何数与 0 异或还是这个数)- 异或运算满足交换律和结合律
基于上述性质,如果我们将数组中的所有数字都异或起来,成对出现的数字都会相互抵消,结果就是那个只出现一次的数字。
代码
java
public int singleNumber(int[] nums) {
int result = 0;
// 遍历数组,将所有元素进行异或运算
for (int num : nums) {
result ^= num;
}
return result;
}
多数元素
题目
思路
Boyer-Moore 投票算法:
这个算法利用了多数元素的特性,可以在线性时间和常量空间复杂度下找到多数元素。
- 算法的核心思路是维护一个候选多数元素
candidate
和计数器count
。- 初始化时
candidate
为null
,count
为 0。 - 当遍历到一个元素时:
- 如果
count == 0
,将当前元素设为candidate
,并将count
设为 1。 - 如果当前元素等于
candidate
,则count
增加 1。 - 如果当前元素不等于
candidate
,则count
减少 1。
- 如果
- 由于多数元素出现次数超过一半,最终的
candidate
一定是多数元素。
- 初始化时
代码
java
public int majorityElement(int[] nums) {
int count = 1;
int candidate = nums[0];
for(int i=1;i<nums.length;i++){
if(count==0){
candidate = nums[i];
}
if(nums[i]==candidate){
count++;
}else{
count--;
}
}
return candidate;
}
颜色分类
题目
思路
使用双指针分别指向头部(low
)和尾部(high
),以及一个遍历指针 i
:
- 当
nums[i] == 0
时,交换nums[i]
和nums[low]
,并让low
和i
向右移动。 - 当
nums[i] == 2
时,交换nums[i]
和nums[high]
,并让high
向左移动。 - 当
nums[i] == 1
时,i
向右移动即可。
通过这种方式,我们可以一次遍历将 0 移到前面,2 移到后面,1 自然排在中间
代码
java
public void sortColors(int[] nums) {
int top=0,tail=nums.length-1;
int x=0;
while(x<=tail){
if(nums[x]==0){
int t = nums[x];
nums[x]=nums[top];
nums[top]=t;
top++;
x++;
}else if(nums[x]==2){
int t = nums[x];
nums[x]=nums[tail];
nums[tail]=t;
tail--;
}else{
x++;
}
}
}
下一个排列
题目
思路
- 从后往前找到第一个降序的数字
nums[i]
,即找到nums[i] < nums[i+1]
的那个位置,这样的位置的右侧是需要调整的部分。 - 在
nums[i]
的右侧找到比nums[i]
大的最小数字nums[j]
,然后交换nums[i]
和nums[j]
。 - 交换后将
nums[i]
右侧的部分进行反转(从降序变为升序),得到的就是字典序的下一个排列。
代码
java
public void nextPermutation(int[] nums) {
int n = nums.length;
int i = n - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
if (i >= 0) {
int j = n - 1;
while (j >= 0 && nums[j] <= nums[i]) {
j--;
}
swap(nums, i, j);
}
reverse(nums, i + 1, n - 1);
}
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
private void reverse(int[] nums, int start, int end) {
while (start < end) {
swap(nums, start, end);
start++;
end--;
}
}
结语
这些题目对我的智商不太友好