2016腾讯编程题:微信红包

题目描述

春节期间小明使用微信收到很多个红包,非常开心。在查看领取红包记录时发现,某个红包金额出现的次数超过了红包总数的一半。请帮小明找到该红包金额。写出具体算法思路和代码实现,要求算法尽可能高效。

给定一个红包的金额数组gifts及它的大小n,请返回所求红包的金额。

测试样例:
[1,2,3,2,2],5
返回:2

解题

题目要求一定存在大于数量一半的数,测试用例出现不到一半的情况。

当一定存在大于一半的数时候,直接求中位数就好了,快排求中位数,在找到中位数,在统计中位数出现的次数,大于一半就是答案否则返回0 

import java.util.*;

public class Gift {
    public int getValue(int[] gifts, int n) {
        // write code here
        //if(n == 134)
       //     return 0;
        quickSort(gifts,0,n-1);
        int count = 0;
        for(int i = 0;i< n;i++){
            if(gifts[i] == gifts[n / 2])
                count++;
        }
        return count>n/2?gifts[n/2]:0;
    }
    // 快速排序取中位数
    public void quickSort(int[] A,int low,int high){
        if(low >= high)
            return;
        int mid = partition(A,low,high);
        quickSort(A,low,mid - 1);
        quickSort(A,mid+1,high);
    }
    public int partition(int [] A,int low ,int high){
        int x = A[high];
        int i = low - 1;
        for( int j = low;j<= high - 1;j++){
            if( A[j] <= x){
                i = i + 1;
                int temp = A[i];
                A[i] = A[j];
                A[j] = temp;
            }
        }
        int temp = A[i+1];
        A[i+1] = A[high];
        A[high] = temp;
        return i + 1;
    }
}

参考剑指Offer

在遍历数组的时候保存两个数:一个是数组中的一个数,一个是次数。当我们遍历到下一个数字的时候,如果下一个数和我们之前保存的数字相同,则次数加一;如果下一个数字和我们之前保存的数组不同,则次数减一。如果次数为0,我们需要更新保存的下一个数字,并把次数记作为1

import java.util.*;

public class Gift {
    public int getValue(int[] A, int n) {
        
        int count = 0;
        int mid = -1;
        for(int i = 0;i< n;i++){
            if(A[i] == mid){
                count++;
            }else {
                if(count!=0){
                    count--;
                }else{
                    mid = A[i];
                    count = 1;
                }
            }
        }
        count = 0;
        for(int i = 0;i< n;i++){
            if(A[i] == mid)
                count++;
        }
        return count>n/2?mid:0;
    }
   
}

剑指offer上第一种方法不需要严格的排序,利用的快排的partition的思想,找到使得某一侧的划分在n/2附近这里就是中位数的位置。

import java.util.*;

public class Gift {
    public int getValue(int[] A, int n) {
        
        int count = 0;
        
        int midId = partition(A,0,n-1);
        while(midId != n/2){
            if(midId > n/2){
                midId = partition(A,0,midId-1);
            }else{
                midId = partition(A,midId+1,n-1);
            }
        }
        int mid = A[midId];
        for(int i = 0;i< n;i++){
            if(A[i] == mid)
                count++;
        }
        return count>n/2?mid:0;
    }
    public int partition(int[] A,int low ,int high){
        int x = A[high];
        int i = low - 1;
        for(int j = low;j< high ;j++){
            if(A[j] <= x){
                i = i + 1;
                int tmp = A[i];
                A[i] = A[j];
                A[j] = tmp;
            }
        }
        int tmp = A[i + 1];
        A[i + 1] = A[high];
        A[high] = tmp;
        return i + 1;
    }
   
}
原文地址:https://www.cnblogs.com/bbbblog/p/5387308.html