2019年9月2日 愿你我有得有失,能哭能笑能尽欢
数组中重复的数字
题目一:在一个长度为n的数组里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但是不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。例如,如果输入长度为7,的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数组2或者3。(n个元素,n种可能的取值)
思路:
可以排序之后,再去寻找有没有重复的元素,但排序一个长度为n 的数组需要O(nlogn) 的时间.可以再进行优化.
遍历一遍数组,将a[i] 中的数字 m 与 i 比较,如果 i= m,遍历下一个.
如果 m 不等于 i, 把 a[i] 和 与 a[m] 中的数字交换,再进行比较,交换.
如果 m 于 a[m] 相等,那就是找到了一个重复的数字.
例子:
0 2 5 4 2
a[0] = 0 下一个
a[1] = 2 1不等于2 将a[1] 与 a[2] 交换
0 5 2 4 2
a[1] =5 1不等于5 将 a[1] 与 a[5] 交换
0 2 2 4 5
a[1] =2 1 不等于 2 将a[1] 与 a[2] 交换 发现a[1]=a[2]=2 此时便找到了重复数 2
由于只是遍历数组+交换位置,所以时间复杂度为O(n),空间复杂度为 O(1)
public static void swap(int arr[],int a,int b)
{
int temp = arr[a];
arr[a]= arr [b];
arr [b] = temp ;
}
public static int getSmall(int [] arr)
{
if (arr.length<0||arr.length<2)
{
return -1;
}
int n = arr.length;
int i=0;
while (i<n)
{
if (arr[i]==i)
{
i++;
}
else if (arr[i]!=i)
{
if (arr[arr[i]]==arr[i])
{
return arr[i];
}
swap(arr,arr[i],i);
i++;
}
}
return -1;
}
public static void main(String[] args) {
int a [] =new int []{0,1};
for (int i = 0; i <a.length ; i++) {
System.out.print(a[i]+"--");
}
System.out.println("");
// swap(a,1,2);
int small = getSmall(a);
System.out.println(small);
}
升级版:
不修改数组
在一个长度为n+1的数组里的所有数字都在1~n范围内,所以数字中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但是不能修改数组。例如,如果输入长度为8的数组{2,3,5,4,3,2,6,7},那么对应的输出是重复的数字2或3。(n+1个元素,n种可能的取值)
思路:
利用二分的思想,将数的范围二分
数字范围都在 1-n之间, 而有n+1 个数,必然有一个数重复, 将数的范围分为 1--m,m+1--n 如果数组中1~m的数字数目超过m,那么重复数字一定出现在这段区间内,反之,重复数字一定出现在m+1~n这段区间内。我们可以重复对包含重复数字的区间进行划分,直到找到这个重复数字。
例子:
2 2 1 3
数的范围为 1-3
第一次二分, mid = 3-1 >>2 =1+1 =2
遍历数组,判断1---2之间的数有几个,返回3
则重复的数在前半段, end =mid
然后分别遍历 1 和 2 在数组中出现的次数
得到 2 出现的次数为2 大于1
则结果为 2
代码:
public static int getSmall(int a[])
{
if(a==null||a.length<1)
{
return -1;
}
int length =a.length;
int bgein = 1;
int end = length-1;
while (end>=bgein)
{
int mid = ((end-bgein)>>1)+bgein ;
int count = nums(a,bgein,mid);
if (end == bgein)
//当mid begin end三者重合时(区间内只有一个数字),判断出现次数是否大于1,
{
if (count>1)
{
return bgein;
}
else
{
break;
}
}
if (count>(mid-bgein+1))
//如果左边的数字出现的次数大于界限所有的数的数量
{
end=mid;
//则将分界值作为右边界
}
else
{
bgein = mid+1;
//否则将分界值后一个数作为左边界
}
}
return -1;
}
private static int nums(int[] a, int bgein, int end) {
if (a==null)
{
return 0;
}
int count = 0 ;
for (int i = 0; i <a.length; i++)
{
if (a[i]>=bgein && a[i]<=end)
{
count++;
}
}
return count;
}
public static void main(String[] args) {
int a [] =new int []{2,2,3,1};
for (int i = 0; i <a.length ; i++) {
System.out.print(a[i]+"--");
}
System.out.println("");
int small = getSmall(a);
System.out.println(small);
}
参考博客:https://mp.csdn.net/postedit?not_checkout=1
二维数组中的查找
题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样一个二维数组和一个整数,判断数组中是否含有该整数。
思路:
最简单的方式直接遍历,等于白给
这个数组中:每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序
从右上角开始,将这个数记做 a,题目中给出的数记做 b
如果 a <b 剔除这一行,遍历这一列,找那个数
如果 a>b , 判断 倒数第二列的第一行的那个数,
如果 a2 < b , 则那个数在这列中,遍历,找到这个数,如果没有就返回 false
例子:
1 5 7
3 6 9
判断是否有 2
首先 7>2 列--
5 >2 列--
1<2 行加加
3>2 且行到了最下面
所有没有 2 这个数
代码:
public class Solution {
public boolean Find(int target, int [][] array) {
if(array.length==0||array[0].length==0||array==null)
{
return false;
}
int row = array.length;
int rows = 0 ;
int col = array[0].length;
int cols = col-1;
while (cols>=0&&rows<=row-1)
{
if (array[rows][cols]==target)
{
return true;
}
else if (array[rows][cols]>target)
{
cols--;
}
else
{
rows++;
}
}
return false;
}
}