纵有疾风起
人生不言弃

剑指Offer第五章面试题(Java版)

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

public class Solution {
    public int MoreThanHalfNum_Solution(int [] array) {
        //判断输入
        if(array==null||array.length==0){
            return 0;
        }
        //先假设为第1个
        int result = array[0];
        int times = 1;

        for (int i = 1; i < array.length; i++) {
            if (times==0) {
                result = array[i];
                times++;
            }else {
                if (result==array[i]) {
                    times++;
                }else {
                    times--;
                }
            }
        }

        if (!CheckMoreThanHalf(array,result)) {//如果没有超过一半
            return 0;
        }

        return result;
    }
    //检查是否超过一半
    public boolean CheckMoreThanHalf(int[] array,int result){
        int times = 0;
        for (int i = 0; i < array.length; i++) {
            if (array[i]==result) {
                times++;
            }
        }
        boolean isMoreThanHalf = true;
        if (times*2<=array.length) {
            isMoreThanHalf = false;
        }
        return isMoreThanHalf;
    }
}

面试题30:最小的K个数

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

import java.util.ArrayList;
import java.util.Collections;

public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {

        ArrayList<Integer> arrayList = new ArrayList<>();
        //判断输入是否合法
        if (input==null||input.length==0||k>input.length||k<=0) {
            return arrayList;
        }
        //判断输入的长度是否与数组相等
        if (k==input.length) {
            for (int i = 0; i < k; i++) {
                arrayList.add(input[i]);
            }
            Collections.sort(arrayList);
            return arrayList;
        }

        int index = Partition(input,0,input.length-1);
        while (k!=index) {
            if (k>index) {//说明k在index的右边
                index = Partition(input,index+1,input.length-1);
            }else {//说明k在index的左边
                index = Partition(input,0,index-1);
            }
        }

        for (int i = 0; i < k; i++) {
            arrayList.add(input[i]);
        }
        Collections.sort(arrayList);

        return arrayList;
    }

    //选择一个关键字,想尽办法将它放到一个位置,使得它左边的值都比它小,
    //右边的值都比它大,我们称这个关键字叫枢轴。
    public int Partition(int[] arr,int low,int high){
        if(arr == null || low<0 || high>=arr.length){
            return 0;
        }

        int pivotkey;
        pivotkey = arr[low];//选取第一个记录作枢轴记录

        while(low<high)//从表的两端向中间扫描
        {
            while(low<high && arr[high]>=pivotkey){//如果大于枢轴值,则下标减一,否则,跳出循环。
                high--;
            }
            Swap(arr, low, high);//交换
            while (low<high && arr[low]<pivotkey){//如果小于枢轴值,则下标加一,否则,跳出循环。
                low++;
            }
            Swap(arr, low, high);//交换
        }
        return low;
    }

    public void Swap(int[] arr,int low,int high){
        int temp = arr[low];
        arr[low] = arr[high];
        arr[high] = temp;  
    }
}

面试题31:连续子数组的最大和

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。你会不会被他忽悠住?

public class Solution {
    public int FindGreatestSumOfSubArray(int[] array) {

        if (array==null||array.length==0) {
            return 0;
        }

        int finalMax=Integer.MIN_VALUE;//初始化为最小值
        int currentSum=0;

        for (int i = 0; i < array.length; i++) {
            //如果之前的总和小于0,表明负数加上array[i]比array[i]还小,直接舍去。
            if (currentSum<=0) {
                currentSum = array[i];
            }
            else {
                currentSum += array[i];
            }

            if (currentSum>finalMax) {
                finalMax = currentSum;
            }
        }
        return finalMax;
    }
}

面试题32: 整数中1出现的次数(从1到n整数中1出现的次数)

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数。

public class Solution {
    /** * 计算十位上1的个数有多少个? * 102 1*10个 10~19 * 112 1*10+(2+1)个 10~19、110 111 112 * 122 (1+1)*10个 10~19、110~119 * @param n * @return */
    public int NumberOf1Between1AndN_Solution(int n) {
        if(n<=0)
            return 0;
        int counts=0;
        int factor = 1;

        int lowerNum=0;
        int currNum=0;
        int higherNum=0;
                                            //102
        while (n/factor!=0) {        //factor=1 10 100
            lowerNum = n-(n/factor)*factor; //0 2 2
            currNum = (n/factor)%10;        //2 0 1
            higherNum = n/(factor*10);      //10 1 0

            switch (currNum) {
                case 0://由更高数字决定
                    counts += higherNum*factor;
                    break;
                case 1://由更高数字和更低数字决定
                    counts += higherNum*factor+lowerNum+1;
                    break;
                default://由更高数字决定
                    counts += (higherNum+1)*factor;
                    break;
            }
            factor *=10;
        }

        return counts;
    }
}

面试题33: 把数组排成最小的数

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

import java.util.Comparator;
import java.util.TreeSet;

public class Solution {
    public String PrintMinNumber(int [] numbers) {
        StringBuilder stringBuilder = new StringBuilder();
        if(numbers==null||numbers.length==0){
            return new String(stringBuilder);
        }

        String[] strings = new String[numbers.length];

        TreeSet<String> sets = new TreeSet<>(
            new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    String combine1 = o1+o2;
                    String combine2 = o2+o1;
                    char[] c1 = combine1.toCharArray();
                    char[] c2 = combine2.toCharArray();

                    for (int i = 0; i < combine1.length();i++) {
                        if (c1[i] < c2[i]) {
                            return -1;
                        }
                        else if (c1[i] > c2[i]){
                            return 1;
                        }

                    }
                    return -1;
                }
            });

        for (int i = 0; i < numbers.length; i++) {
            strings[i] = Integer.toString(numbers[i]);
            sets.add(strings[i]);
            System.out.println(strings[i]);
        }

        for (String set : sets) {
            System.out.println(set);
            stringBuilder.append(set);
        }

        return new String(stringBuilder);
    }
}

面试题34:丑数

把只包含因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

public class Solution {
    public int GetUglyNumber_Solution(int index) {

        if (index<=0) {
            return 0;
        }
        //用于保存丑数
        int[] uglyNumbers = new int[index];
        uglyNumbers[0] = 1;//第一个丑数为1
        int nextUglyIndex = 1;//下一个丑数的索引

        int multiply2 = 0;
        int multiply3 = 0;
        int multiply5 = 0;

        while (nextUglyIndex < index) {
            //[0]=1 [1]=2 [2]=3 [3]=4 [4]=5 [5]=6
            //0[2] 0[3] 0[5]
            //1[4] 0[3] 0[5]
            //1[4] 1[6] 0[5]
            //2[6] 1[6] 0[5]
            //2[6] 1[6] 1[10]
            //3[8] 2[9] 1[10]
            int min = Min(uglyNumbers[multiply2]*2,
                    uglyNumbers[multiply3]*3, uglyNumbers[multiply5]*5);

            uglyNumbers[nextUglyIndex] = min;//取三者的最小者作为下一个丑数

            while (uglyNumbers[multiply2]*2<=uglyNumbers[nextUglyIndex]) {
                multiply2++;
            }
            while (uglyNumbers[multiply3]*3<=uglyNumbers[nextUglyIndex]) {
                multiply3++;
            }
            while (uglyNumbers[multiply5]*5<=uglyNumbers[nextUglyIndex]) {
                multiply5++;
            }

            nextUglyIndex++;
        }

        int ugly = uglyNumbers[nextUglyIndex-1];

        return ugly;
    }

    public int Min(int number1,int number2,int number3){
        int min=number1;
        if (number2<min) {
            min = number2;
        }
        if (number3<min) {
            min = number3;
        }
        return min;
    }
}

面试题35: 第一个只出现一次的字符位置

在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符的位置。若为空串,返回-1。位置索引从0开始

public class Solution {
    public int FirstNotRepeatingChar(String str) {

        if (str==null||str.length()>1000) {
            return -1;
        }
        if (str.length()==0) {
            return -1;
        }

        char[] chs = str.toCharArray();
        //用于存放每字符的次数
        int[] hashtable = new int[256];

        //初始化
        for (int i = 0; i < hashtable.length; i++) {
            hashtable[i]=0;
        }

        for (int i = 0; i < chs.length; i++) {
            hashtable[chs[i]]++;
        }

        for (int i = 0; i < chs.length; i++) {
            if(hashtable[chs[i]]==1){
                return i;
            }
        }
        return -1;
    }
}

面试题36: 数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

public class Solution {
    public int InversePairs(int [] array) {
        if (array==null || array.length==0) {
            return 0;
        }
        //辅助数组
        int[] temp = new int[array.length];
        //初始为原始值的副本
        for (int i = 0; i < temp.length; i++) {
            temp[i] = array[i];
        }

        int count = InversePairsCore(array, temp, 0, array.length-1);

        return count;      
    }

    //合并array到temp中
    public int InversePairsCore(int[] array,int[] temp,int start,int end){
        //只有一个数的时候,直接将改值赋于temp中,逆序直接为零。
        if (start==end) {
            temp[start] = array[start];
            return 0;
        }

        int length = (end+start)/2;//取中

        //将存储与temp中的数据进行合并到array
        int left = InversePairsCore(temp, array, start, length);//左边子数组的个数
        int right = InversePairsCore(temp, array, length+1, end);//右边子数组的个数

        //i初始化为前半段的最后一个数字的下标
        int i = length;
        //j初始化为后半段的最后一个数字的下标
        int j = end;

        int indexCopy = end;
        int count=0;

        while (i>=start && j>=length+1) {
            if (array[i]>array[j]) {
                temp[indexCopy--] = array[i--];
                count += j-length;
            }else {
                temp[indexCopy--] = array[j--];
            }
        }

        while (i>=start) {
            temp[indexCopy--] = array[i--];
        }
        while (j>=length+1) {
            temp[indexCopy--] = array[j--];
        }

        return left+right+count;
    }
}

面试题37:两个链表的第一个公共结点

输入两个链表,找出它们的第一个公共结点。

/* public class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } }*/
public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {

        if (pHead1==null||pHead2==null) {
            return null;
        }

        int length1 = 0;
        int length2 = 0;

        //假设pHead1为短链表,pHead2为长链表。
        ListNode shortNode = pHead1;
        ListNode longNode = pHead2;

        //统计长短链表的长度
        while (shortNode!=null) {
            length1++;
            shortNode = shortNode.next;
        }
        while (longNode!=null) {
            length2++;
            longNode = longNode.next;
        }

        //计算长度差
        int diffLen = (length1>length2)?(length1-length2):(length2-length1);

        shortNode = pHead1;
        longNode = pHead2;

        if (length1>length2) {
            shortNode = pHead2;
            longNode = pHead1;
        }
        //先让长链表走diffLen步
        for (int i = 0; i < diffLen; i++) {
            longNode = longNode.next;
        }

        while (longNode!=null&&shortNode!=null) {
            if (longNode==shortNode) {
                return longNode;
            }
            longNode=longNode.next;
            shortNode=shortNode.next;
        }

        return null;
    }
}

原文链接:https://blog.csdn.net/scgaliguodong123_/article/details/48448355

本站声明:网站内容来源于网络,如有侵权,请联系我们,我们将及时处理。

未经允许不得转载:起风网 » 剑指Offer第五章面试题(Java版)
分享到: 生成海报

评论 抢沙发

评论前必须登录!

立即登录