剑指Offer(一) 数组中重复的数字,二维数组中的查找

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;
    }
}
    

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值