第三十四天
540 有序数组中的单一元素
给你一个仅由整数组成的有序数组,其中每个元素都会出现两次,唯有一个数只会出现一次。
请你找出并返回只出现一次的那个数。
你设计的解决方案必须满足 O(log n)
时间复杂度和 O(1)
空间复杂度。
方法
由于数组中所有的元素都出现了两次,只有一个元素出现了一次,如果我们不考虑这个唯一出现一次的元素,那么按照数组的下标来看,偶数位置的元素总是重复元素的第一个元素,而奇数位置的元素总是重复元素的第二个元素。当我们引入这个唯一出现一次的元素之后,在这个元素之后,规律就变成了奇数位置为重复元素的第一个元素,偶数位置的元素为重复元素的第二个元素。利用这个特点,我们可以使用二分查找来处理这个问题,当mid
是偶数的时候,我们比较一下mid
和mid+1
是否相等,如果相等,说明这个唯一出现一次的元素在mid
后面,否则就在mid
前面;同理当mid
是奇数的时候,我们比较mid
和mid-1
即可,如果mid
和mid-1
位置上的元素相等,说明唯一出现一次的元素在mid
后面,否则在mid
前面。
class Solution {
public int singleNonDuplicate(int[] nums) {
int l = 0, r = nums.length - 1;
while (l <= r){
int mid = (l + r) >> 1;
if ((mid & 1) == 1){
if (nums[mid - 1] == nums[mid]) l = mid + 1;
else r = mid - 1;
}
else{
if (mid + 1 < nums.length && nums[mid] == nums[mid + 1]) l = mid + 1;
else r = mid - 1;
}
}
return nums[l];
}
}
384 打乱数组
给你一个整数数组 nums
,设计算法来打乱一个没有重复元素的数组。打乱后,数组的所有排列应该是 等可能 的。
实现 Solution
class:
-
Solution(int[] nums)
使用整数数组nums
初始化对象 -
int[] reset()
重设数组到它的初始状态并返回 -
int[] shuffle()
返回数组随机打乱后的结果
方法
对于每一个位置上的数字,我们生成一个从0
到length - 1
的随机数,然后让其与该位置的数交换,对数组中的每一个数都进行此操作即可。
class Solution {
private int[] nums;
private int length;
private Random rand;
public Solution(int[] nums) {
this.nums = nums;
rand = new Random(2333);
}
public int[] reset() {
return nums;
}
public int[] shuffle() {
int[] res = nums.clone();
for (int i = 0; i < res.length; ++i){
int exchange = rand.nextInt(res.length);
int temp = 0;
temp = res[i];res[i] = res[exchange];res[exchange] = temp;
}
return res;
}
}
202 快乐数
编写一个算法来判断一个数 n
是不是快乐数。
「快乐数」 定义为:
-
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
-
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
-
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n
是 快乐数 就返回 true
;不是,则返回 false
。
方法
模拟操作6
次,如果不是快乐数,返回false
,否则返回true
。
class Solution {
public boolean isHappy(int n) {
int res = 0;
for (int i = 0; i < 6; ++i){
res = 0;
while (n > 0){
res += (n % 10) * (n % 10);
n /= 10;
}
n = res;
if (n == 1) return true;
}
return false;
}
}
149 直线上最多的点数
给你一个数组 points
,其中 points[i] = [xi, yi]
表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。
方法
直接用最直接的方法即可,我们维护一个Line->int
的map
,用于记录每一条直线上的点数,返回map
中的最大值即可。
class Solution {
public int maxPoints(int[][] points) {
if (points.length == 1) return 1;
Map<Line, Integer> map = new HashMap<>();
for (int i = 0; i < points.length - 1; ++i){
for (int j = i + 1; j < points.length; ++j){
int deltaA = points[i][0] - points[j][0];
int deltaB = points[i][1] - points[j][1];
if (deltaA == 0) {
Line k = new Line(0,Integer.MAX_VALUE, 0, points[i]);
map.put(k, map.getOrDefault(k, 1) + 1);
continue;
}
if (deltaB == 0){
Line k = new Line(0,0, Integer.MAX_VALUE, points[i]);
map.put(k, map.getOrDefault(k, 1) + 1);
continue;
}
int flag = getSign(deltaA, deltaB);
int common = GCD(Math.abs(deltaA), Math.abs(deltaB));
Line k = new Line(flag,Math.abs(deltaB) / common, Math.abs(deltaA) / common, points[i]);
map.put(k, map.getOrDefault(k, 1) + 1);
}
}
int res = 0;
for (int i : map.values()) res = Math.max(res, i);
return res;
}
public int GCD(int m, int n){
if (m % n == 0) return n;
return GCD(n, m % n);
}
public int getSign(int a, int b){
if (a * b < 0) return -1;
return 1;
}
}
class Point{
int x;int y;
Point(int[] a){x = a[0]; y = a[1];}
@Override public boolean equals(Object p){
Point cmp = (Point) p;
return cmp.x == x && cmp.y == y;
}
@Override public int hashCode(){return x | y;}
}
class Line{
Point startPoint;
int a;
int b;
int flag;
public Line(int f, int _a, int _b, int[] s){flag = f;a = _a;b = _b;startPoint = new Point(s);}
@Override
public boolean equals(Object k){
Line cmp = (Line)k;
return flag == cmp.flag && cmp.a == a && cmp.b == b && startPoint.equals(cmp.startPoint);
}
@Override
public int hashCode(){
return flag | a | b | startPoint.hashCode();
}
@Override
public String toString(){
return flag + startPoint.x + " " + startPoint.y + " " + a + "/" + b;
}
}