zoukankan      html  css  js  c++  java
  • 数字在排序数组中出现的次数

    题目描述
    统计一个数字在排序数组中出现的次数。

    方法一
    最简单的方法就是遍历整个数组。没什么好说的,很low.

    	/**
    	 * 方法一
    	 * @param array
    	 * @param k
    	 * @return
    	 */
    	public int GetNumberOfK(int [] array , int k) {
    		if(array == null || array.length == 0) {
    			return 0;
    		}
    
    		int times = 0;
    		for (int i = 0; i < array.length; i++) {
    			if(array[i] == k) {
    				++times;
    			}
    		}
    		
    		return times;
    	}
    

    方法二
    数组是有序的,我们可以利用二分查找。直观的一个思路就是通过二分查找获得一个k在数组中的下标,然后顺序的在k的前面和后面寻找和k相等的数。

    	/**
    	 * 方法二
    	 */
    	public int GetNumberOfK_2(int [] array , int k) {
    		if(array == null || array.length == 0) {
    			return 0;
    		}
    		int low = 0, high = array.length - 1, mid = 0, times = 0;
    		while(low <= high) {
    			mid = (low + high) / 2;
    			if(k < array[mid]) {
    				high = mid - 1;
    			}
    			else if(k > array[mid]) {
    				low = mid + 1;
    			}
    			else {
    				times = 1;
    				break;
    			}
    		}
    		
    		for (low = mid - 1; (low >= 0) && (array[low] == k); low--) {
    			times += 1;
    		}
    		for (low = mid + 1; (low < array.length) && (array[low] == k); low++) {
    			times += 1;
    		}
    		
    		return times;
    	}
    

    但是很可能面试官还不满意,还想要更快的方法。

    方法三
    通过二分查找获得数组中第一个k的下标和最后一个k的下标,然后下标相减就是出现的次数。思路是通过二分找到一个k,先判断这个数字是不是第一个k,如果中间数字的前面一个数字不是k,那么此时中间数字刚好就是第一个k,如果中间数字的前面一个数字也是k,那么第一个k肯定在数组的前半段,继续二分,这是递归的过程。
    寻找第一个k下标的方法(递归):

    	private int FetFirstK(int[] elem, int k, int start, int end) {
    		if(start > end) {
    			return -1;
    		}
    		
    		int mid = (start + end) / 2;
    		if(elem[mid] > k) {
    			return FetFirstK(elem, k, start, mid - 1);
    		}
    		else if(elem[mid] < k) {
    			return FetFirstK(elem, k, mid + 1, end);
    		}
    		else if(mid - 1 >= 0 && elem[mid - 1] == k) {
    			return FetFirstK(elem, k, start, mid - 1);
    		}
    		else {
    			return mid;
    		}
    	}
    

    寻找最后一个k的下标的方法(非递归):

    	private int FetLastK(int[] elem, int k, int start, int end) {
    		int mid = (start + end) / 2;
    		while(start <= end) {
    			if(elem[mid] > k) {
    				end = mid - 1;
    			}
    			else if(elem[mid] < k) {
    				start = mid + 1;
    			}
    			else if(mid + 1 <elem.length && elem[mid + 1] == k) {
    				start = mid + 1;
    			}
    			else {
    				return mid;
    			}
    			
    			mid = (start + end) / 2;
    		}
    		
    		return -1;
    	}
    

    主方法:

    	/**
    	 * 方法三
    	 * @param array
    	 * @param k
    	 * @return
    	 */
    	public int GetNumberOfK_3(int [] array , int k) {
    		if(array == null || array.length == 0) {
    			return 0;
    		}
    		
    		int firstK = FetFirstK(array, k, 0, array.length - 1);
    		int lastK = FetLastK(array, k, 0, array.length - 1);
    		if(firstK != -1 && lastK != -1) {
    			return lastK - firstK + 1;
    		}
    		return 0;
    
    	}
    

    方法四
    因为数组中都是整数,所以可以稍微变一下,不是搜索k的两个位置,而是搜索k-0.5和k+0.5这两个数应该插入的位置,然后相减即可。

    	/**
    	 * 方法四
    	 * @param array
    	 * @param k
    	 * @return
    	 */
    	public int GetNumberOfK_4(int [] array , int k) {
    		if(array == null || array.length == 0) {
    			return 0;
    		}
    		
    		return biSearch(array, k + 0.5) - biSearch(array, k - 0.5);
    	}
    	
    	private int biSearch(int[] elem, double num) {
    		int start = 0, end = elem.length - 1, mid = (start + end) / 2;
    		while(start <= end) {
    			if(elem[mid] < num) {
    				start = mid + 1;
    			}
    			else if(elem[mid] > num) {
    				end = mid - 1;
    			}
    			mid = (start + end) / 2;
    		}
    		return start;
    	}
    
  • 相关阅读:
    深度分析:java8的新特性lambda和stream流,看完你学会了吗?
    花了三天整理,Spring Cloud微服务如何设计异常处理机制?还看不懂算我输
    做了两年java,这些高性能高可用高并发的技术架构你都知道吗?
    面试阿里,字节跳动90%会被问到的微服务,你确定不进来看看吗?
    阿里面试官:小伙子,你给我说一下前后端分离的接口规范是什么?
    深度分析:面试阿里,字节跳动,美团几乎都会被问到的阻塞队列
    1. 线性DP 1143. 最长公共子序列
    1. 线性DP 300. 最长上升子序列 (LIS)
    GC 的认识(转) https://github.com/qcrao/Go-Questions/blob/master/GC/GC.md#1-什么是-gc有什么作用
    缓存淘汰算法--LRU算法
  • 原文地址:https://www.cnblogs.com/lishanlei/p/10707678.html
Copyright © 2011-2022 走看看