03:1.数组中重复的数字
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
输入:
[2, 3, 1, 0, 2, 5, 3]
输出: 2 或 3
/**
* 查找重复的数字
*
* @param arr 指定数组
* @return int 未找到返回-1
* @author Huikf
* @since 18:42 2022/3/20
*/
public static int getRepeatNum(int[] arr) {
Set<Integer> set = new HashSet<>();
for (int i : arr) {
if (set.contains(i)) {
return i;
}
set.add(i);
}
return -1;
}
提示:
进阶:
如何证明 n u m s numsnums 中至少存在一个重复的数字?
你可以在不修改数组 n u m s numsnums 的情况下解决这个问题吗?
你可以只用常量级 O ( 1 ) O(1)O(1) 的额外空间解决这个问题吗?
思路
不能修改原数组,故不能用移动元素让下标和值相对应的方法,也不能用排序的方法
只能用O(1)的空间,故不能用HashSet和新数组打卡标记的方法
时间复杂度小于O ( n 2 )
故不能用暴力嵌套两个for循环遍历数组两次的方法
1<=nums[i]<=n
/**
* 查找重复的数字
* [2,3,3,2,5,4,6,7]
*
*
* <p>
* 采用二分查找的方法
*
* @param arr 指定数组
* @return int
* @author Huikf
* @since 18:42 2022/3/20
*/
public static int getRepeatNum(int[] arr) {
//最小值
int left = 1;
//最大值
int right = arr.length - 1;
while (left < right) {
//中间值
int mid = (left + right) / 2;
//获取在这个区间数组中元素在这个区间出现的次数,
//正常来说left-mid+1 刚好等于这个count,说明没有重复 ,如上述数组 1~4之间count=4(mid-left+1),
//但实际上count=5,说明在[left,mid]区间中有重复值,所以把mid赋值给right,即在[1,4]中寻找重复值,直到退出循环
int count = getCount(arr, left, mid);
if (count > (mid - left + 1)) {
//在左边
right = mid;
} else {
left = mid + 1;
}
}
return left;
}
private static int getCount(int[] arr, int left, int mid) {
int count = 0;
for (int i : arr) {
if (i >= left && i <= mid) {
count++;
}
}
return count;
}
04:二维数组中的查找
/**
* 一个数字是否存在矩阵,该矩阵横向竖向递增
* <p>
* 思路:从右上方开始查找 比右上方大x--,小则y++,直到相等
*
* @param matrix 二维矩阵
* @param target 目标值
* @return boolean
* @author Huikf
* @since 19:49 2022/3/20
*/
public static boolean isExist(int[][] matrix, int target) {
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
return false;
}
//右上方坐标
int x = matrix.length - 1;
int y = 0;
while (x >= 0 && y <= matrix[0].length - 1) {
if (matrix[x][y] == target) {
return true;
} else if (matrix[x][y] > target) {
x--;
} else {
y++;
}
}
return false;
}
05 3.替换空格
/**
* 字符串替换 空格替换成%20
*
* @param s 输入字符串
* @return java.lang.String
* @author Huikf
* @since 19:59 2022/3/20
*/
public static String replaceSpace(String s) {
StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) {
if (c == ' ') {
sb.append("%20");
} else {
sb.append(c);
}
}
return sb.toString();
}
合并有序数组
/**
* 合并有序数组
* 数组A的长度=A的长度+B的长度
* 采用双指针法
*
* @param A A数组
* @param m A数组长度
* @param B B数组
* @param n B数组长度
* @author Huikf
* @since 21:26 2022/3/20
*/
public void mergeSortArr(int[] A, int m, int[] B, int n) {
//指向A数组最后元素的位置
int last1 = m - 1;
//指向B数组最后元素的位置
int last2 = n - 1;
//指向拼接后插入的位置
int last = m + n - 1;
while (last1 >= 0 && last2 >= 0) {
if (A[last1] >= B[last2]) {
A[last] = A[last1];
last1--;
} else {
A[last] = B[last2];
last2--;
}
last--;
}
//当last1<0(数组B有剩余)时退出,然后将未遍历完的B数组拷贝到A数组中。
//或者last2<0(数组A有剩余)时退出,这时,说明B数组已经全部合并到A数组中,这下面该意思为:把B数组从0位置到last2+1位置元素拷贝到A数组的从0起始位置
System.arraycopy(B, 0, A, 0, last2 + 1);
}
06 4.从尾到头打印链表
public static int[] reversePrint(ListNode head) {
if (head == null) {
return new int[]{};
}
Stack<Integer> stack = new Stack<>();
ListNode cur = head;
while (cur != null) {
stack.push(cur.val);
cur = cur.next;
}
int[] arr = new int[stack.size()];
for (int i = 0; i < arr.length; i++) {
arr[i] = stack.pop();
}
return arr;
}
07 5.重构二叉树
、、
打印从1到最大的n位数
/**
* 打印从1到最大的n位数
* 10^n-1
*
* @param n n
* @return int[]
* @author huikf
* @since 2022/3/22 10:55
*/
public int[] print(int n) {
int v = (int) Math.pow(10, n) - 1;
int[] res = new int[v];
for (int i = 0; i < res.length; i++) {
res[i] = i + 1;
}
return res;
}