hot100-一刷-17技巧(共5道题)
136. 只出现一次的数字
题目描述
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
示例 1 :
输入:nums = [2,2,1]
输出:1
示例 2 :
输入:nums = [4,1,2,1,2]
输出:4
示例 3 :
输入:nums = [1]
输出:1
提示:
1 <= nums.length <= 3 * 104
-3 * 104 <= nums[i] <= 3 * 104
除了某个元素只出现一次以外,其余每个元素均出现两次。
代码实现
分析:
异或:
- 0 ^ x = x
- x ^ x = 0;
代码:
class Solution {
public int singleNumber(int[] nums) {
// 0 ^ x = x x ^ x = 0;
int ans = 0;
for (int x : nums) {
ans ^= x;
}
return ans;
}
}
169. 多数元素
题目描述
给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:nums = [3,2,3]
输出:3
示例 2:
输入:nums = [2,2,1,1,1,2,2]
输出:2
提示:
n == nums.length
1 <= n <= 5 * 104
-109 <= nums[i] <= 109
进阶:尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。
代码实现
分析:
代码:
class Solution {
public int majorityElement(int[] nums) {
int votes = 0;
int ans = 0;
for(int n : nums){
if(votes == 0){
ans = n; // 假设当前元素为“众数”
}
if(n == ans){
votes++;
}else{
votes--;
}
}
return ans;
}
public int majorityElement2(int[] nums) {
Arrays.sort(nums);
return nums[nums.length / 2];
}
}
75. 颜色分类
题目描述
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库内置的 sort 函数的情况下解决这个问题。
示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
示例 2:
输入:nums = [2,0,1]
输出:[0,1,2]
提示:
n == nums.length
1 <= n <= 300
nums[i] 为 0、1 或 2
进阶:
你能想出一个仅使用常数空间的一趟扫描算法吗?
代码实现
分析:
代码:
class Solution {
public void sortColors(int[] nums) {
int red = -1;
int blue = nums.length - 1;
// i <= blue i = blue 时还有一个元素还没有看,还需要比较一次
for(int i = 0; i <= blue; i++){
// System.out.println(i);
if(nums[i] == 0){
red++;
swap(nums, i, red);
}else if(nums[i] == 1){
continue;
}else{
swap(nums, i, blue);
blue--;
i--; // 回退一步,重新看下第i个是1还是0
}
// for(int n : nums){
// System.out.print(n);
// }
// System.out.print("\n");
}
}
private void swap(int[] nums, int index1, int index2){
int t = nums[index1];
nums[index1] = nums[index2];
nums[index2] = t;
// System.out.println("swap" +": " + t + "<--->" + nums[index1] );
}
}
31. 下一个排列
题目描述
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
给你一个整数数组 nums ,找出 nums 的下一个排列。
必须 原地 修改,只允许使用额外常数空间。
示例 1:
输入:nums = [1,2,3]
输出:[1,3,2]
示例 2:
输入:nums = [3,2,1]
输出:[1,2,3]
示例 3:
输入:nums = [1,1,5]
输出:[1,5,1]
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 100
代码实现
分析:
代码:
class Solution {
public void nextPermutation(int[] nums) {
int len = nums.length;
for(int i = len - 2; i >= 0; i--){
// 从后往前找到第一个升序排列, 目的是为了找到「小数」
if (nums[i] < nums[i+1]){
// 找到小数 nums[i], 因为从后往前找的第一个升序排列,
// 所以此时[i+1, end) 为降序排列, 降序排列中有可能大于这个「小数」
// 需要在这里从后往前找到第一个大于这个「小数」的「大数」,后面是降序,这个「大数」尽可能小
for(int j = len - 1; j > i; j--){
if(nums[i] < nums[j]){
// 「大数」nums[j] 「小数」nums[i]
// 交换, 同时让「小数」原来位置i,往后的地方,升序排列, 因为原来是降序, 所以翻转一下就是升序了。
// 注意交换之后,i后面也是降序的, 因为找的是第一个比nums[i]大的
swap(nums, i, j);
reverse(nums, i+1, len-1);
return;
}
}
}
}
//如果没有提前退出,那么就是没碰到逆序遍历是降序的,全是升序,说明最大了
reverse(nums,0,len-1);
}
private void swap(int[] nums, int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
//由于nums[i] < nums[i+1],我们可以知道,到满足这个条件的前提,是必须存在递增,
//从后面往前,遍历了很多个才碰到第一个符合条件的,
//那么说明从第一个符合条件开始往后,后面的肯定都是递减,是降序的,所以逆置即可最快重新排序。
// []
private void reverse(int[] nums, int left, int right){
while (left < right){
swap(nums, left, right);
left++;
right--;
}
}
}
287. 寻找重复数
题目描述
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。
你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。
示例 1:
输入:nums = [1,3,4,2,2]
输出:2
示例 2:
输入:nums = [3,1,3,4,2]
输出:3
示例 3 :
输入:nums = [3,3,3,3,3]
输出:3
提示:
1 <= n <= 105
nums.length == n + 1
1 <= nums[i] <= n
nums 中 只有一个整数 出现 两次或多次 ,其余整数均只出现 一次
进阶:
如何证明 nums 中至少存在一个重复的数字?
你可以设计一个线性级时间复杂度 O(n) 的解决方案吗?
代码实现
分析:
代码:
class Solution {
public int findDuplicate(int[] nums) {
int slow = 0;
int fast = 0;
slow = nums[slow];
fast = nums[nums[fast]];
while(fast != slow){
slow = nums[slow];
fast = nums[nums[fast]];
}
int head = 0;
int point = slow;
while(head != point){
head = nums[head];
point = nums[point];
}
return head;
}
}
本文来自博客园,作者:chendsome,转载请注明原文链接:https://www.cnblogs.com/chendsome/p/18644644