【算法】-- 【数组循环右移k位,数组第k个最小的值,数组中只出现一次的元素,数组唯一重复的元素,用递归法求数组的最大元素】

01 如何把一个数组循环右移k位

例如:数组{1,2,3,4,5,6,7,8,9}右移两位
第一步 逆序数组子序列 1234567,数组变为765432189
第二步 逆序列数组子序列89,数组变为765432198
第三步 全部逆序,数组变为891234567

/**
     * 交换数组
     * @param arr
     * @param b  开始的下标
     * @param e  结束的下标
     */
    public static void reverse(int arr[],int b,int e){
        for (;b<e;b++,e--){
            int tmp = arr[b];
            arr[b]=arr[e];
            arr[e]=tmp;
        }
    }

    //右移k位
    public static void shift_k(int arr[],int k){
        int n=arr.length;
        k=k%n;//为了防止k比n大,右移k位和k%n位结果一样
        reverse(arr,0,n-k-1);
        reverse(arr,n-k,n-1);
        reverse(arr,0,n-1);
    }

    public static void main(String[] args) {
        int []arr={1,2,3,4,5,6,7,8,9};
        shift_k(arr,2);
        for (int i:arr){
            System.out.print(i+"  ");
        }
    }

02 如何找出数组中第k个最小的数

剪枝法
选一个数tmp = a[n-1] 作为枢纽,把比它小的数都放在它的左边,比它大的数都放在它的右边,然后判断tmp的位置,如果它的位置为k-1,那么它就是死第k个最小的数;如果它的位置小于k-1,那么说明第k个小的元素一定在数组的右半部分,采用递归的方法在数组的右半部分继续查找;否则第k个小的元素在数组的左半部分,采用递归的方法在左半部分继续查找

 public static int quitSort(int array[],int low,int high,int k){
        int i,j;
        int tmp;
        if (low>high)
            return Integer.MAX_VALUE;
        i=low;
        j=high;
        tmp=array[i];
        while (i<j){
            while (i<j&&array[j]>tmp)
                j--;
            if (i<j)
                array[i++]=array[j];
            while (i<j&&array[i]<tmp)
                i++;
            if (i<j)
                array[j--]=array[i];
        }
        array[i]=tmp;
        if (i+1==k)
            return tmp;
        else if (i+1>k)
            return quitSort(array,low,i-1,k);
        else
            return quitSort(array,i+1,high,k);
    }

    public static void main(String[] args) {
        int a[] ={10,5,1,9,2,0,18,4};
        int k=2;
        int i = quitSort(a, 0, a.length - 1, k);
        System.out.println("第 "+k+" 小的值为: "+i);
    }

03 如何找出数组中只出现一次的数字

问题描述:一个整形数组里除了一个数字之外,其他数字都出现了两次。找出这个只出现1次的数字。要求时间复杂度为O(n),空间复杂度为O(1)
异或法:任何数字异或它自己都等于0

    public static int findNotDouble(int[] arr){
        int n=arr.length;
        int result=arr[0];
        for (int i=1;i<n;i++){
            result ^=arr[i];
        }
        return result;
    }
    public static void main(String[] args) {
        int arr[]={1,2,1,2,3,4,5,4,5};
        System.out.println( findNotDouble(arr));

    }

引申:如果题目改成数组A中,一个整形数组里除了一个数字之外,其他数字都出现3次,嘛呢如何找出这个数?

    public static int findOnce(int a[],int appearTimes){
        int n=a.length;
        int[] bitCount = new int[32];
        //计算数组中所有数组对应的二进制数各个位置上出现1次的数
        for (int i=0;i<n;i++){
            for (int j=0;j<32;j++){
                bitCount[j]+=((a[i]>>j)&1);
            }
        }
        //若某位上的结果不能被整除,则可定目标数字在这一位上
        int appearOne =0;
        for (int i=0;i<32;i++){
            if (bitCount[i]%appearTimes!=0)
                appearOne+=(1<<i);
        }
        return appearOne;
    }

    public static void main(String[] args) {
        int arr1[]={1,1,1,2,2,2,3,4,4,4};
        System.out.println( findOnce(arr1,1));
    }

04 如何找出数组中唯一的重复元素

问题描述:数组a[N] ,1~N-1这N-1个数存放在a[N]中,其中某个数重复1次。写一个函数,找出被重复的数字。要求没个数组元素只能访问1次,并且不用辅助空间。

蛮力法:
采用数组求和,因为只用一个数字重复1次,而又是连续的,根据累加和原理,对数组的所有项求和,然后减去1~N-1的和,及所求的重复数。

 public static int xor_FindDup(int []a){
        int n=a.length;
        int tmp1=0;
        int tmp2=0;
        for (int i=0;i<n-1;i++){
            tmp1+=(i+1);
            tmp2+=a[i];
        }
        tmp2+=a[n-1];
        int result =tmp2-tmp1;
        return result;
    }
    
    public static void main(String[] args) {
        int a[]={1,2,3,3,4,5};
        System.out.println(xor_FindDup(a));
    }

异或法:
每两个相异的执行异或运算之后,结果为1,每两个相同的数执行异或运算之后,结果为0,所以数组a[N]中的N个数异或结果与1~N-1异或的结果在做异或运算,得到的值即为所求。

  public static int xor_FindDup1(int arr[]){
        int n=arr.length;
        int result=0;
        for (int i=0;i<n;i++)
            result ^=arr[i];
        for (int i=1;i<n;i++)
            result ^=i;
        return result;
    }

    public static void main(String[] args) {
        int a[]={1,2,3,3,4,5};
        System.out.println(xor_FindDup1(a));
    }

空间换时间法:

   public static int findInteger(int[] a){
        int n=a.length;
        boolean[] arrayFlag=new boolean[n];
        int result=0;
        for (int i=0;i<n;i++){
            arrayFlag[i]=false;
        }
        for (int i=0;i<n;i++){
            if (arrayFlag[a[i]]==false)
                arrayFlag[a[i]]=true;
            else
                result =a[i];
        }
        return result;
    }


    public static void main(String[] args) {
        int a[]={1,2,3,3,4,5};
        System.out.println(findInteger(a));
    }

引申:取值为[1,n-1]含n个元素的整数数组,至少存在一个重复数,及可能存在多个重复数,O(n)时间内找出其中任意一个重复数,例如:array[]={1,2,2,4,5,4},2和4均是重复元素

取反法:
如果遍历到数组中元素为i,那么把a[i]的值取反,如果i在数组出现了1次,那么a[i]会经过两次取反操作,a[i]的值跟原始的值相等,且为正数;如果i出现了1次,那么a[i]的值为原始值得相反数,且为负数,可以根据这个原理实现

    public static int findInteger1(int[] a){
        int n=a.length;
        int result=Integer.MAX_VALUE;
        for (int i=0;i<n;i++){
            if (a[i]>0){
                a[a[i]]=-a[a[i]];
            }else{
                a[-a[i]]=-a[-a[i]];
            }
        }
        for(int i=1;i<n;i++){
            if (a[i]>0)
                result=i;
            else
                a[i]=-a[i];

        }
        return result;
    }


    public static void main(String[] args) {
        int a[]={1,2,3,3,4,5};
        System.out.println(findInteger1(a));
    }

判断单链表是否有环法:
本题转化为,已知一个单链表中存在环,找出换的入口点。

 public static int findInteger2(int a[]){
        int x,y;
        x=y=0;
        do {
            x=a[a[x]];
            y=a[y];
        }while (x!=y);
        x=0;
        do {
            x=a[x];
            y=a[y];
        }while (x!=y);
        return x;
    }

    public static void main(String[] args) {
        int a[]={1,2,3,3,4,5};
        System.out.println(findInteger2(a));
    }

05 如何用递归方法求一个整数数组的最大元素

先定义一个变量max为数组的第一个元素,然后从第二个元素开始遍历,咋及便利的过程中,每个元素都与max的值比较,若个元素的值比max的值大,则吧该元素的值赋给max。

    private static int max(int a,int b){
        return a>b?a:b;
    }

   public static int maxNum(int a[],int begin){
        int length=a.length-begin;
        if(length==1){
            return a[begin];
        }else {
            return max(a[begin],maxNum(a,begin+1));
        }
    }

    public static void main(String[] args) {
        int a[]={11,1,24,8,9,12,6,7,20};
        System.out.println(maxNum(a,0));
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值