• 面试题29:数组中出现次数超过一半的数字


    题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。

    分析:

    如果一个数字才数组中出现的次数超过了数组长度的一半,那么对这个数组进行排序,位于数组中间位置的那个数就是出现次数超过一半的那个数。对数组排序的时间复杂度是O(nlog(n)),但是对于这道题目,还有更好的算法,能够在时间复杂度O(n)内求出。我们写过快速排序算法,其中的Partition()方法是一个最重要的方法,该方法返回一个index,能够保证index位置的数是已排序完成的,在index左边的数都比index所在的数小,在index右边的数都比index所在的数大。那么本题就可以利用这样的思路来解。

    1. 通过Partition()返回index,如果index==mid,那么就表明找到了数组的中位数;如果index<mid,表明中位数在[index+1,end]之间;如果index>mid,表明中位数在[start,index-1]之间。知道最后求得index==mid循环结束。
    2. 根据求得的index,遍历一遍数组,每当出现一个等于index所指向的数时time++,最后判断time是否大于数组长度的一半,如果大于则表明index所指向的数就是所求的数,如果不是,则表明不存在一个数出现的次数超过数组长度的一半。

    代码实例:

    View Code
    #include<iostream>
    #include<stdlib.h>
    using namespace std;
    
    //函数声明
    int MoreThanHalf(int arry[],int start,int end,int len);//函数入口
    int Partition(int arry[],int start,int end);//返回一个index,使index左边的数都比index所在的数小,index右边的数都比index所在数大
    bool CheckMoreThanHalf(int arry[],int len,int result);//判断一个数在数组中是否有超过一半
    
    int Partition(int arry[],int start,int end)
    {
        int pivotkey=arry[start];
        while(start<end)
        {
            while(start<end&&arry[end]>=pivotkey)
                end--;
            arry[start]=arry[end];
            while(start<end&&arry[start]<=pivotkey)
                start++;
            arry[end]=arry[start];
        }
        arry[start]=pivotkey;
        return start;
    }
    
    bool CheckMoreThanHalf(int arry[],int len,int result)
    {
        int time=0;
        for(int i=0;i<len;i++)
        {
            if(arry[i]==result)
                ++time;
        }
    
        bool isMoreThanHalf=true;
        if(time*2<=len)
            isMoreThanHalf=false;
        return isMoreThanHalf;
    }
    
    int MoreThanHalf(int arry[],int start,int end,int len)
    {
        if(arry==NULL&&len<=0)
            return -1;
    
        int index=Partition(arry,start,end);
        int middle=len/2;//中间位置
        while(index!=middle)
        {
            if(index>middle)//如果调整数组以后获得的index大于middle,则继续调整start到index-1区段的数组
                index=Partition(arry,start,index-1);
            else//否则调整index+1到end区段的数组
                index=Partition(arry,index+1,end);
        }
        //最后获取的index=middle,此时在middle左边的数小于arry[middle],在其右边的数大于arry[middle]
        int result=arry[middle];
        if(!CheckMoreThanHalf(arry,len,result))
            return -1;
    
        return arry[middle];
    }
    
    void main()
    {
        //int arry[]={5,1,7,3,0,2,8};//定义数组
        int arry[]={2,2,1,1,3};//定义数组
        int len=sizeof(arry)/sizeof(int);//求数组长度
    
        int half=MoreThanHalf(arry,0,len-1,len);
        cout<<half<<endl;
    
        system("pause");
    }

    题目变种

    一个文件中有每一个保存一个单词,其中有一个单词出现的次数超过一半,求这个次数超过一半的单词。

    解体思路

    这道题目其实本质上跟前面的求出现次数超过一半的数是一样的,只不过是这里要求的是单词出现次数,而前面是整数出现次数。如果是整数的话,可以通过一个整型数组来完成求中位数的操作。但是这里是字符串了,我们想再用求中位数的方法,只能通过LinkedList这个集合累来完成。

    首先我们遍历一次问价,将所有单词都保存到LinkedList当中去,然后求排在中间的那个单词。LinkedList中的元素使有序的,不像ArrayList中的元素那样是无序的。而且List中允许元素重复。

    代码实现

    View Code
    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.util.Iterator;
    import java.util.LinkedList;
    
    public class GetMoreThanHalfWords {
    
        public static void main(String args[]) {
            GetMoreThanHalfWords gmthw = new GetMoreThanHalfWords();
            
            LinkedList<String> list =new LinkedList<String>();
            gmthw.buildLinkedList(list);
            //两种输出LinkedList的方法
            //gmthw.printLinkedList(list);
            //gmthw.printLinkedList2(list);
            System.out.println(gmthw.getMoreThanHalf(list));
            
            /**
             * 测试String的compareTo方法
            String a="apple";
            String b="orange";
            System.out.println(a.compareTo(b));
            System.out.println(b.compareTo(a));
            */
            
        }
    
        // 第一步:创建LinkedList,将文件中的单词保存到LinkedList当中。
        public void buildLinkedList(LinkedList<String> list) {
            try {
                FileReader reader = new FileReader("words2.txt");
                BufferedReader br = new BufferedReader(reader);
    
                String s = null;
                while ((s = br.readLine()) != null) {
                    list.add(s);
                }
                br.close();
                reader.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        public String getMoreThanHalf(LinkedList<String> list)
        {
            int len=list.size();
            int mid=len/2;
            int start=0;
            int end=len-1;
            int index=partition(list,len,start,end);
            while(index!=mid)//index总会等于mid的
            {
                if(index>mid)
                {
                    end=index-1;
                    index=partition(list,len,start,end);
                }
                else
                {
                    start=index+1;
                    index=partition(list,len,start,end);
                }
            }
            //到这里index=mid
            return list.get(index);
        }
        
        public int partition(LinkedList<String> list,int len,int start,int end)
        {
            String s=list.get(start);
            while(start<end)
            {
                //找出第一个
                while(start<end&&s.compareTo(list.get(end))<=0)
                    end--;
                list.set(start, list.get(end));
                while(start<end&&s.compareTo(list.get(start))>=0)
                    start++;
                list.set(end, list.get(start));
            }
            list.set(start, s);
            return start;
        }
        
        // 打印LinkedList中的值
        //方法1
        public void printLinkedList(LinkedList<String> list) {
            Iterator it = list.iterator();
            while (it.hasNext()) {
                System.out.println(it.next());
            }
        }
        //方法2
        public void printLinkedList2(LinkedList<String> list) {
            for(int i=0;i<list.size();i++)
            {
                System.out.println(list.get(i));
            }
        }
    }
  • 相关阅读:
    开发之前的思考-UI结构设计
    UI事件监听的击穿
    实战开发中UI资源制作标准
    巧用九宫格以减少UI资源量
    UI元素的相对自适应
    UI开发核心问题-UI随屏幕自适应
    制作滚动视图(ScrollView)
    制作复选框(Toggle)
    制作下拉菜单(PopupList)
    制作输入框(Input)
  • 原文地址:https://www.cnblogs.com/xwdreamer/p/2489728.html
Copyright © 2020-2023  润新知