• 三道题 2015.8.26(二进制中1的个数,数组中出现次数超过一半的数字,最大(小)的K个数)


    1:二进制中1的个数

    第一种做法:最直接的将数对二作除法和余数操作。统计余数中1的个数

    第二种做法:将该二进制数和1做与运算,然后再右移操作。

    但是这里有一个问题就是右移运算符,将最右边的几位丢弃。并且容易陷入死循环,剑指offer第79页专门提出这个问题并给出了解释

    如果数字是一个无符号数,则用0填充最左边的n位,如果数字是一个有符号的数字,则用数字的符号位填补最左边的n位。

    第三种做法也是我认为最好的做法:将该整数与减去1之后得到的数做与运算。

    int c = 10;
    
    System.out.println(Integer.toBinaryString(c));
    

      

    2:给定一个数组,知道该数组中有一个数出现的次数超过整体的一半,找出这个数

    排序数组的中位数一定是这个数,而如果完全排序,会耗费很多的时间。而针对快速排序,每一趟都能确定一个元素的最终位置。

    首先快速排序的算法一定要掌握:下面附上代码:

    //确定一趟排序元素的位置
    public static int identityTheIndex (int[] A,int low,int high){
    		
    		int key = A[low];
    		while(low<high){
    			while(low<high&&A[high]>=key){
    				high--;
    			}
    			A[low] = A[high];
    			while(low<high&&A[low]<=key){
    				low++;
    			}
    			A[high] = A[low];
    		}
    		A[low]=key;
    		return low;
    		
    	}
    
    
    递归进行排序
    public static void quictSort(int[] A,int low, int high){
    		if(low <high){
    			int index =  identityTheIndex(A,low,high);
    			quictSort(A,low,index-1);
    			quictSort(A,index+1,high);
    		}
    	}
    

      受到快速排序的启示,可以边排序边判断,代码如下:

    public static int moreThanHalfNumber(int[] A,int length){
    		int mid = length >> 1;
    		int high = length - 1;
    		int low = 0;
    		int index = identifyTheIndex(A,low,high);
    		while(index!=mid){
    			if(index>mid){
    				high = index - 1;
    				index = identifyTheIndex(A,low,high);
    			}
    			else{
    				low = index + 1;
    				index =identifyTheIndex(A,low,high);
    			}
    		}
    		int result = A[mid];
    		return result;
    		
    	}
    

      第二种方法:考虑遍历数组的时候保存两个值:一个是数组中的一个数字,一个是次数,当遍历下一个数字的时候,如果下一个数字和之前保存的数字相同,则次数加1,如果下一个数字和之前保存的数字不同,则次数减1,如果次数为0,则需要保存下一个数字,并把次数设为1.由于要找的数字出现的次数比其他所有数字出现的次数之后还要多,那么要找的数字肯定是最后一次把次数设为1时对应的数字。代码如下:

    public static int moreThanHalfNumber2(int[] A,int length){
    		int result = A[0];
    		int time = 1;
    		for(int  i = 1;i<length;i++){
    			if(time == 1){
    				result = A[i];
    				time = 1;
    			}
    			else if(result == A[i]){
    				time ++ ;
    			}
    			else{
    				time -- ;
    			}
    		}
    		return result;
    	}
    

      3:最小(大)的k个数

    这道题可以借助上题的思想主要确定第K个元素的位置,最直接的想法就是快速排序。

    第二种方法特别适合处理海量数据,首先创建一个大小为K的数据容器来存储最小的K的数字,接着每次从输入的n个数中读入一个数,如果容器中已有的数字少于K个,则直接读入;如果已经有K个,也就是容器已满,这时只能替换。首先要找出这K 个数字中的最大的数,如果接下来的数字小于最大的数将替换,否则继续遍历下一个数

    因此,容器满了需要做3件事:

    1)K个整数中找出最大的数

    2)有可能在这个容器中删除最大数

    3)有可能要插入一个新的数字

    如果用二叉树来实现这个数据容器,就能在O(logk)时间内完成,对于n个输入数字而言,总的时间效率就是O(nlogk)

    很容易想到最大堆。

    下面先复习一下建堆,以及堆排序的过程。

    建堆:从下向上,建好的堆,根节点最大或最小。代码如下:

    public static void createMaxdHeap(int[] data, int lastIndex) {  
            for (int i = (lastIndex - 1) / 2; i >= 0; i--) {  
                // 保存当前正在判断的节点  
                int k = i;  
                // 若当前节点的子节点存在  
                while (2 * k + 1 <= lastIndex) {  
                    // biggerIndex总是记录较大节点的值,先赋值为当前判断节点的左子节点  
                    int biggerIndex = 2 * k + 1;  
                    if (biggerIndex < lastIndex) {  
                        // 若右子节点存在,否则此时biggerIndex应该等于 lastIndex  
                        if (data[biggerIndex] < data[biggerIndex + 1]) {  
                            // 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的值  
                            biggerIndex++;  
                        }  
                    }  
                    if (data[k] < data[biggerIndex]) {  
                        // 若当前节点值比子节点最大值小,则交换2者得值,交换后将biggerIndex值赋值给k  
                        swap(data, k, biggerIndex);  
                        k = biggerIndex;  
                    } else {  
                        break;  
                    }  
                }  
            }  
        }  
      
    

      堆排序:将建好的堆根节点输出,然后将其与最后一个叶子节点交换,然后重新建堆,这个时候建堆的元素个数少一。

    代码如下:

     public static void heapSort(int[] data) {  
            for (int i = 0; i < data.length; i++) {  
                createMaxdHeap(data, data.length - 1 - i);  
                swap(data, 0, data.length - 1 - i);  
                print(data);  
            }  
        }  
    
    
    public static void swap(int[] data, int i, int j) {  
            if (i == j) {  
                return;  
            }  
            data[i] = data[i] + data[j];  
            data[j] = data[i] - data[j];  
            data[i] = data[i] - data[j];  
        }  
    

      而这道题只是要求找出最小的K个数并没有要求有序,因此可以借助建堆的操作,代码如下:

    public static void createMaxdHeap(int[] data, int lastIndex) {  
            for (int i = (lastIndex - 1) / 2; i >= 0; i--) {  
                // 保存当前正在判断的节点  
                int k = i;  
                // 若当前节点的子节点存在  
                while (2 * k + 1 <= lastIndex) {  
                    // biggerIndex总是记录较大节点的值,先赋值为当前判断节点的左子节点  
                    int biggerIndex = 2 * k + 1;  
                    if (biggerIndex < lastIndex) {  
                        // 若右子节点存在,否则此时biggerIndex应该等于 lastIndex  
                        if (data[biggerIndex] < data[biggerIndex + 1]) {  
                            // 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的值  
                            biggerIndex++;  
                        }  
                    }  
                    if (data[k] < data[biggerIndex]) {  
                        // 若当前节点值比子节点最大值小,则交换2者得值,交换后将biggerIndex值赋值给k  
                        swap(data, k, biggerIndex);  
                        k = biggerIndex;  
                    } else {  
                        break;  
                    }  
                }  
            }  
        }  
    	
    	
    	public static void print(int[] data) {  
            for (int i = 0; i < data.length; i++) {  
                System.out.print(data[i] + "	");  
            }  
            System.out.println();  
        }    
    
    
    public static int[] getFirstNumber(int[] A, int k){
    		
    		int[] B = new int[k];
    		for(int i =0;i<k;i++){
    			B[i] = A[i];
    		}
    		heapSort(B);
    		int count = k;
    		while(count!=A.length){
    			/*int minmumValue = B[0];
    			int maxmumValue = B[k-1];*/
    			int maxmumValue = B[0];
    			//System.out.println("对排序后最小的元素:"+minmumValue);
    			if(maxmumValue>A[count]){
    				int temp = A[count];
    				B[0] = temp;
    				
    			}
    			System.out.println("替换元素之后的B:");
    			print(B);
    			System.out.println("......................................");
    			heapSort(B);
    			count++;
    		}
    		return B;
    	}
    	
    public static void main(String[] args) {
    		
    		int[] A = {80,55,45,7,8,6,3,10,2,1};
    		int k = 4;
    		int[] C = getFirstNumber(A,k);
    		System.out.print("最xiao的K个数为:");
    		for(int i = 0;i<k;i++){
    			System.out.print(C[i] + "	"); 
    		}
    }
    
    程序的输出结果为:
    80	55	45	7	
    80	55	45	7	
    80	55	45	7	
    80	55	45	7	
    替换元素之后的B:
    8	55	45	7	
    ......................................
    55	8	45	7	
    55	8	45	7	
    55	8	45	7	
    55	8	45	7	
    替换元素之后的B:
    6	8	45	7	
    ......................................
    45	8	6	7	
    45	8	6	7	
    45	8	6	7	
    45	8	6	7	
    替换元素之后的B:
    3	8	6	7	
    ......................................
    8	7	6	3	
    8	7	6	3	
    8	7	6	3	
    8	7	6	3	
    替换元素之后的B:
    8	7	6	3	
    ......................................
    8	7	6	3	
    8	7	6	3	
    8	7	6	3	
    8	7	6	3	
    替换元素之后的B:
    2	7	6	3	
    ......................................
    7	3	6	2	
    7	3	6	2	
    7	3	6	2	
    7	3	6	2	
    替换元素之后的B:
    1	3	6	2	
    ......................................
    6	3	1	2	
    6	3	1	2	
    6	3	1	2	
    6	3	1	2	
    最xiao的K个数为:6	3	1	2	
    

      

  • 相关阅读:
    tr 字符转换命令
    Log4cpp配置文件及动态调整日志级别的方法
    Ubuntu使用总结
    vim安装与配置(进阶版)
    [转载] Linux CC与GCC的区别
    C语言基础总结
    VIM之ctags & Taglist 插件
    vim之基础配置
    使用问题:Chrome卡死崩溃
    Ubuntu16.10安装之后的软件安装
  • 原文地址:https://www.cnblogs.com/gracyandjohn/p/4761701.html
Copyright © 2020-2023  润新知