第一题
思路:递归
public class 第一题07 {
public static void main(String[] args) {
int[] arr = {2,5,7};
int res1 = maxNumber1(arr, 22571);
int res2 = maxNumber2(arr, 22571);
System.out.println(res1);
System.out.println(res2);
}
public static int maxNumber1(int[] arr, int limit) {
Arrays.sort(arr);
limit--;
int offset = 1;
while (offset <= limit / 10){
offset *= 10;
}
int ans = process1(arr,limit,offset);
if (ans != -1){
return ans;
}else {
offset /= 10;
int res = 0;
while (offset > 0){
res += arr[arr.length - 1] * offset;
offset /= 10;
}
return res;
}
}
private static int process1(int[] arr, int limit, int offset) {
if (offset == 0){
return limit;
}
int cur = (limit / offset) % 10;
int near = near(arr,cur);
if (near == -1){
return -1;
}else if (arr[near] == cur){
int ans = process1(arr,limit,offset / 10);
if (ans != -1){
return ans;
}else if (near > 0){
near--;
return (limit / (offset * 10)) * (offset * 10) + arr[near] * offset + rest(arr,offset / 10);
}else {
return -1;
}
}else {
return (limit / (offset * 10)) * (offset * 10) + arr[near] * offset + rest(arr,offset / 10);
}
}
public static int maxNumber2(int[] arr, int limit) {
// arr里面是不重复的数字,且只包含0~9
// 5, 8 , 2
// 2, 5, 8
Arrays.sort(arr);
limit--;
// <= limit 且最大的数字
// 68886
// 10000
// 为了取数而设计的!
// 457
// 100
int offset = 1;
while (offset <= limit / 10){
offset *= 10;
}
// arr, 2 5 8
// limit--, 试图去追平的数字
// offset, 扣出limit中每一位的数字!
// 可以使用arr中的数字,期望得到尽可能接近limit的结果,并且位数一样
// 能做到,返回的结果就是答案
// 如果做不到和limit位数一样!返回-1
int ans = process(arr,limit,offset);
if (ans != -1){
return ans;
}else {
offset /= 10;
int res = 0;
while (offset > 0){
res += arr[arr.length - 1] * offset;
offset /= 10;
}
return res;
}
}
// 可以选哪些数字,都在arr里,arr是有序的,[2,5,8]
// limit : <= limit 且尽量的大!
// offset : 为limit服务的,就是为了提取limit的每一位数字
private static int process(int[] arr, int limit, int offset) {
// offset 1000 100 10 1 0
// offset == 0,意味着,之前的数字,全都可以追平,返回limit
// 之前的数字和limit完全一样,且limit所有数字都一样
if (offset == 0){
return limit;
}
// limit中还有数字,没遍历到,
// (limit / offset) % 10
// 当前数字是谁,提取出来
int cur = (limit / offset) % 10;
// 2 5 8
// <=4
// 2 ....8888
int near = near(arr,cur);
if (near == -1){
return -1;
}else if (arr[near] == cur){// 找出来的数字,真的和当前数字cur一样
// 当前位,追平了!
// 看看后续能不能走的通!
int ans = process(arr,limit,offset / 10);
// 1) 走通了!
// 2) 走不通,
// A :当前位还有下降的空间!
// B :当前位没有下降的空间!
if (ans != -1){
return ans;
}else if (near > 0){
near--;
return (limit / (offset * 10)) * offset * 10 + (arr[near] * offset) + rest(arr, offset / 10);
}else {
return -1;
}
}else {// arr[near] < cur
return (limit / (offset * 10)) * offset * 10 + (arr[near] * offset) + rest(arr, offset / 10);
}
}
// 比如offset = 100
// 一共3位数
// 那么就把arr中最大的数字x,拼成xxx,返回
// 比如offset = 10000
// 一共5位数
// 那么就把arr中最大的数字x,拼成xxxxx,返回
public static int rest(int[] arr, int offset) {
int rest = 0;
while (offset > 0) {
rest += arr[arr.length - 1] * offset;
offset /= 10;
}
return rest;
}
private static int near(int[] arr, int cur) {
int l = 0;
int r = arr.length - 1;
int ans = -1;
while (l <= r){
int m = (l + r) / 2;
if (arr[m] <= cur){
ans = m;
l = m + 1;
}else {
r = m - 1;
}
}
return ans;
}
}
第二题
public class 第二题07 {
public static void main(String[] args) {
int[] arr = {3,5,1,2,4,4};
int res1 = findDuplicate1(arr);
int res2 = findDuplicate2(arr);
System.out.println(res1);
System.out.println(res2);
int[] arr1 = {1,2,2,3,4,5,6,7,8};
int res = findDuplicateSorted(arr1);
System.out.println(res);
}
// 符合题目要求的、无序数组,找重复数
// 时间复杂度O(N),额外空间复杂度O(1)
//快慢指针
public static int findDuplicate1(int[] arr) {
if (arr == null || arr.length < 2){
return -1;
}
int slow = arr[0];
int fast = arr[arr[0]];
while (slow != fast){
slow = arr[slow];
fast = arr[arr[fast]];
}
fast = 0;
while (slow != fast){
slow = arr[slow];
fast = arr[fast];
}
return slow;
}
//数学公式
public static int findDuplicate2(int[] arr) {
int res1 = 0;
int res2 = 0;
for (int i = 1;i < arr.length;i++){
res1 += i;
}
for (int num : arr){
res2 += num;
}
return res2 - res1;
}
// 符合题目要求的、有序数组,找重复数
// 时间复杂度O(logN),额外空间复杂度O(1)
public static int findDuplicateSorted(int[] arr) {
if (arr == null || arr.length < 2) {
return -1;
}
int l = 0;
int r = arr.length - 1;
int ans = -1;
while (l <= r){
int m = (l + r) / 2;
if ((m - 1 >= 0 && arr[m - 1] == arr[m]) || (m + 1 < arr.length && arr[m + 1] == arr[m])){
ans = arr[m];
break;
}else if (m - l == arr[m] - arr[l]){
l = m + 1;
}else {
r = m - 1;
}
}
return ans;
}
}