数据结构之数组(上)

1.寻找数组中的最大值与最小值
(1)问题分解法,把该问题看做两个独立的问题,每次分别找出最小值和最大值,一共需要遍历两次数组,比较次数为2N
(2)取单元素法,维持两个变量min和max,每次取出一个元素,先和已经找到的最小值进行比较,再与已找到的最大值进行比较,只需要遍历一次数组即可
(3)取双元素法,维持两个变量,每次比较相邻两个数,较大者与max比较,较小者与min比较,比较次数为1.5N
(4)数组元素移位法,将数组中相邻的元素分在一组,每次比较两个相邻的数,将较大值交换至这两个数左边,较小者防御右边。对大者组扫描一次找出最大值,对小者组扫描一次找出最小值,需要比较的次数为1.5N~2N,但需要改变数组结果
(5)分治法,将数组划分成两半,分别找出两边的最小值最大值,则最小值最大值分别是两边最小值的较小者、两边最大值的较大者,比较次数为1.5N

public class MaxMin {
    static int MAX;
    static int MIN;
    public static void getMaxAndMin2(int arr[]){
        MAX=arr[0];
        MIN=arr[0];
        for(int i=1;i<arr.length;i++){
            if(arr[i]<MIN){
                MIN=arr[i];
            }
            else if(arr[i]>MAX){
                MAX=arr[i];
            }
        }
    }
    public static void getMaxAndMin3(int arr[]){
        MAX=arr[0];
        MIN=arr[0];
        int len=arr.length;
        for(int i=1;i<len-1;i=i+2){
            if(i+1>len){//最后一个数
                if(arr[i]>MAX){
                    MAX=arr[i];
                }
                if(arr[i]<MIN){
                    MIN=arr[i];
                }
            }
            if(arr[i]>arr[i+1]){
                if(arr[i]>MAX){
                    MAX=arr[i];
                }
                if(arr[i+1]<MIN){
                    MIN=arr[i+1];
                }
            }
            if(arr[i]<arr[i+1]){
                if(arr[i+1]>MAX){
                    MAX=arr[i+1];
                }
                if(arr[i]<MIN){
                    MIN=arr[i];
                }
            }
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int [] array={7,3,19,40,4,7,1};
//      getMaxAndMin2(array);
        getMaxAndMin3(array);
        System.out.println(MAX);
        System.out.println(MIN);

    }

}

2.找出数组中第二大数
(1)先通过排序对数组进行排序,然后根据数组下标访问数组中第二大的数。最快的排序算法一般为快排,时间复杂度为O(nlogn),根据下标访问需要遍历一边数组,时间复杂度为O(n),所以总时间复杂度为O(nlogn)
(2)先定义两个变量:最大值,初始元素位数组首元素;二大值,初始元素为最小负整数。然后遍历数组。如果数组元素的值比最大值大,则最大值赋给二大值,最大值更改为该数组元素;如果数组元素比最大值小,最大值不变,比较该元素与二大值,如果该元素比二大值大,则将该元素赋给二大值

public class SecondMax {

    public static int getSecondMax(int [] array){
        int count=array.length;
        int max=array[0];
        int secondMax=Integer.MIN_VALUE;
        for(int i=1;i<count;i++){
            if(array[i]>max){
                secondMax=max;
                max=array[i];
            }
            else{
                if(array[i]>secondMax){
                    secondMax=array[i];
                }
            }
        }
        return secondMax;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int [] array={7,3,19,40,4,7,1};
        System.out.println(getSecondMax(array));

    }

}

3.找出数组中重复元素最多的数

package array;
import java.util.*;
import java.util.Map.Entry;
/*
 * 找出数组中重复元素最多的数
 * eg:{1,1,2,2,4,4,4,4,5,5,6,6,6}
 * 1出现2次,2出现2次,4出现4次,5出现2次,6出现3次,输出为元素4
 */

public class FindMostFrequentArray {

    /*方法一:空间换时间
     * 除非内存空间足够大,一般不采取
     */

    /*方法二:引入Map映射表记录每一个元素出现的次数
     * 判断次数大小,进而找出重复次数最多的元素
     */
    public static int findMostFrequentInArray(int []a){
        int result=0;
        int most=0;

        Map<Integer,Integer> map=new HashMap<Integer,Integer>();
        for(int i=0;i<a.length;i++){
            if(map.containsKey(a[i])){//map中已经包含,个数加一
                map.put(a[i], map.get(a[i])+1);
            }
            else{//map中不包含,新加入
                map.put(a[i], 1);
            }
        }

        Iterator it=map.entrySet().iterator();
        while(it.hasNext()){
            Map.Entry entry=(Entry)it.next();
            int key=(int)entry.getKey();
            int value=(int)entry.getValue();
            if(most<value){
                most=value;
                result=key;
            }
        }
        return result;
//      return most;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int array[]={1,5,4,3,4,4,5,4,5,5,6,6,6,6,6};
//      int number=findMostFrequentInArray(array);
        System.out.println(findMostFrequentInArray(array));

    }

}

4.求数组中两两相加等于20的组合种数

package array;

import java.util.Arrays;

/* 求数组中两两相加等于20的组合种数
 * 给定一个数组{1,7,17,2,6,3,14}
 * 满足条件的有两对组合17+3=20,6+14=20
 */
public class FindSum {
    /*方法一:蛮力法
     * 采用两重循环遍历数组,判断两个数的和是否为20
     * 时间复杂度为O(n^2)
     */
    public static void findSum1(int [] a,int sum){
        int len=a.length;
        for(int i=0;i<len;i++){
            for(int j=i;j<len;j++){
                if(a[i]+a[j]==sum){
                    System.out.println(a[i]+","+a[j]);
                }
            }
        }
    }

    /*方法二:排序法
     * 先对数组元素进行排序,可选择堆排序或者快排,时间复杂度为O(nlogn)
     * 然后对排序后的数组分别从前到后和从后到前遍历,从前往后遍历begin,从后往前end
     * 当arr[begin]+arr[end]<20时,如果存在两个数和为20,那么这两个数一定在[begin+1,end]
     * 当arr[begin]+arr[end]>20时,如果存在两个数和为20,那么这两个数一定在[begin,end+1]
     * 这个过程的时间复杂度为O(n)
     */

    public static void findSum2(int [] a,int sum){
        Arrays.sort(a);
        int begin=0;
        int end=a.length-1;
        while(begin<end){
            if(a[begin]+a[end]<sum){
                begin++;
            }
            else if(a[begin]+a[end]>sum){
                end--;
            }
            else{
                System.out.println(a[begin]+","+a[end]);
                begin++;
                end--;
            }
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int []array={1,7,17,2,6,3,14};
//      findSum1(array,20);
        findSum2(array,20);
    }

}

5.数组循环右移k位

package array;
/*
 * 把一个数组循环右移k位
 * eg:12345678循环右移2位变为78123456
 * 1.逆序数组子序列123456,变为65432178
 * 2.逆序数组子序列78,变为65432187
 * 3.全部逆序,变为78123456
 * 该算法进行了三次逆序操作,时间复杂度为O(n)
 */
public class ReverseShift {
    public static void reverse(int [] a,int b,int e){
        for(;b<e;b++,e--){
            int temp=a[e];
            a[e]=a[b];
            a[b]=temp;
        }
    }

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

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int array[]={1,2,3,4,5,6,7,8};
        shift_k(array,2);
        for(int i:array){
            System.out.print(i+" ");
        }

    }

}

LeetCode上有道题,给定一个链表,将链表向右旋转k个位置,其中k为非负数,eg:
Given1->2->3->4->5->NULLand k =2,
return4->5->1->2->3->NULL

public static ListNode test(ListNode head,int k){
        if(k==0 || head==null || head.next==null){
            return head;
        }
        ListNode preHead=new ListNode(0);
        preHead.next=head;
        ListNode cur=head;
        ListNode pre=head;
        int total=0;
        for(total=1;cur.next!=null;total++){//求出链表长度
            cur=cur.next;
        }
        for(int i=1;i<total-k%total;i++){//向前走length-n
            pre=pre.next;
        }
        cur.next=preHead.next;
        preHead.next=pre.next;
        pre.next=null;
        return preHead.next;
    }

6.找出数组中第k个最小的数

package array;
public class MinK {
    /*
     * 方法一:排序,排序后数组第k-1位置上的数即为数组的第k个最小的数
     * 最好的时间复杂度为O(nlogn)
     */

    /*
     * 方法二:剪枝法,采用快排思想实现
     * 选一个数temp=a[n-1]作为枢纽,把比它小的数放在它的左边,比它大的数放在右边
     * 然后判断它的位置,如果等于k-1,那么它就是第k个最小的数
     * 如果它的位置小于k-1,说明第k个小的元素一定在右边,采用递归方法在数组右边继续查找
     */

    public static int quikSort(int [] array, int low, int high, int k){
        int i,j,temp;
        if(low>high){
            return Integer.MIN_VALUE;
        }
        i=low;
        j=high;
        temp=array[i];
        while(i<j){
            while(i<j && array[j]>=temp){
                j--;
            }
            if(i<j){//比中轴小的记录移到低端
                array[i++]=array[j];
            }
            while(i<j && array[i]<temp){
                i++;
            }
            if(i<j){//比中轴大的记录移到高端
                array[j--]=array[i];
            }
        }
        array[i]=temp;//中轴记录到尾
        if(i==k-1){
            return temp;
        }
        else if(i>k-1){
            return quikSort(array,low,i-1,k);
        }
        else{
            return quikSort(array,i+1,high,k);
        }
    }

    public static int getKMin(int []array, int k){
        if(array==null){
            return Integer.MIN_VALUE;
        }
        if(array.length<k){
            return Integer.MIN_VALUE;
        }
        return quikSort(array,0,array.length-1,k);
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int []a={1,5,2,6,8,0,6};
        System.out.println(getKMin(a,1));
        System.out.println(getKMin(a,2));
        System.out.println(getKMin(a,3));
        System.out.println(getKMin(a,4));

    }

}

7.找出数组中只出现一次的数字

package array;
/*
 * 找出数组中只出现一次的数字
 */
public class FindOnce {
    /*
     * 问题:一个整型数组除了一个数字之外,其他数字都出现了两次(偶数),找出这个只出现一次的数字
     * 要求:时间复杂度是O(n),空间复杂度是O(1)
     * 排序:从第一个开始遍历,比较相邻的两个数,时间复杂度为O(nlogn)
     * 异或:任何一个数字异或自己都为0,异或0都为自己
     */
    public static int findOnceTwo(int []a){
        int result=a[0];
        for(int i=1;i<a.length;i++){
            result=result^a[i];
        }
        return result;
    }
    /*
     * 问题:一个整型数组除了一个数字之外,其他数字都出现了三次,找出这个只出现一次的数字
     * 如果数组中所有数字出现n次,所有数字对应的二进制数中,各个位上1出现的个数均可被n整除,eg:{1,1,1,2,2,2}
     * 二进制:01,01,01,10,10,10,第0位有3个1,第1位有3个1,是3的倍数
     * 所以:假设出现一次的该数为a,那么去掉a后其他所有数字对应的二进制数的每个位置出现的个数为3的倍数
     * 可以对数组中所有数字对应的二进制数中各个位置上的1的个数对取余,就可以得到出现1次的这个数的二进制表示
     * 既适合于奇数,也适合于偶数
     */
    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 [] array={1,2,3,2,4,3,5,4,1};
        int [] a={1,2,1,2,4,2,4,4,1,3};
        System.out.println(findOnceTwo(array));
        System.out.println(findOnce(a,3));
    }

}

8.递归求解一个整数数组的最大元素
最大值求法在1中已经进行了介绍,递归求法是:递归的求解“数组第一个元素”与“数组中其他元素组成的子数组的最大值”的最大值

public class MaxDiGui {

    public 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) {
        // TODO Auto-generated method stub
        int[] num={0,16,2,3,4,5,6,7,8};
        System.out.println(maxnum(num,0));

    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值