【剑指offer】31-40题

31.求连续子数组(包含负数)的最大和

思路:若和小于0,则将最大和置为当前值,否则计算最大和。

代码实现

    public int FindGreatestSumOfSubArray(int[] array) {
        if (array == null || array.length == 0)
            return 0;
        int cur = array[0];
        int greast = array[0];

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

            if (cur > greast) {
                greast = cur;
            }
        }
        return greast;
    }

32.从1到非负整数n中1出现的次数

思路:若百位上数字为0,百位上可能出现1的次数由更高位决定;若百位上数字为1,百位上可能出现1的次数不仅受更高位影响还受低位影响;若百位上数字大于1,则百位上出现1的情况仅由更高位决定

代码实现

    public long CountOne2(long n) {
        long count = 0; // 1的个数
        long i = 1;  // 当前位
        long current = 0,after = 0,before = 0;

        while((n / i) != 0) {
            before = n / (i * 10); // 高位
            current = (n / i) % 10; // 当前位
            after = n - (n / i) * i;  // 低位

            if (current == 0)
                //如果为0,出现1的次数由高位决定,等于高位数字 * 当前位数
                count = count + before * i;
            else if(current == 1)
                //如果为1,出现1的次数由高位和低位决定,高位*当前位+低位+1
                count = count + before * i + after + 1;
            else if (current > 1)
                // 如果大于1,出现1的次数由高位决定,(高位数字+1)* 当前位数
                count = count + (before + 1) * i;
            //前移一位
            i = i * 10;
        }
        return count;
    }

解法二:公式法

    public int NumberOf1Between1AndN_Solution(int n){
        int count=0;

        for(int i = 1; i <= n; i *= 10){
            int a = n / i; // 高位
            int b = n % i; // 低位
            count += (a+8) / 10 * i;
            if(a % 10 == 1){
                count += b + 1;
            }
        }
        return count;
    }

33.输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个

思路:先将整型数组转换成String数组,然后将String数组排序,最后将排好序的字符串数组拼接出来。关键就是制定排序规则。或使用比较和快排的思想,将前面的数和最后的数比较,若小则放到最前面,最后再递归调用。

代码实现

    public String PrintMinNumber(int [] numbers) {
        if(numbers == null || numbers.length == 0)
            return "";
        int len = numbers.length;
        String[] str = new String[len];
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < len; i++){
            str[i] = String.valueOf(numbers[i]);
        }
        Arrays.sort(str,new Comparator<String>(){
            @Override
            public int compare(String s1, String s2) {
                String c1 = s1 + s2;
                String c2 = s2 + s1;
                return c1.compareTo(c2);
            }
        });

        for(int i = 0; i < len; i++){
            sb.append(str[i]);
        }
        return sb.toString();
    }

34.求从小到大的第N个丑数。丑数是只包含因子2、3和5的数,习惯上我们把1当做是第一个丑数。

思路:乘2或3或5,之后比较取最小值。

代码实现

    public int GetUglyNumber_Solution(int index) {
        if (index <= 0)
            return 0;
        int[] arr = new int[index];
        arr[0] = 1;
        int multiply2 = 0;
        int multiply3 = 0;
        int multiply5 = 0;

        for (int i = 1; i < index; i++) {
            int min = Math.min(arr[multiply2] * 2,Math.min(arr[multiply3] * 3,arr[multiply5] * 5));
            arr[i] = min;
            if (arr[multiply2] * 2 == min)
                multiply2++;
            if (arr[multiply3] * 3 == min)
                multiply3++;
            if (arr[multiply5] * 5 == min)
                multiply5++;
        }
        return arr[index - 1];
    }

35.在一个字符串(1<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置

思路:利用LinkedHashMap保存字符和出现次数。

代码实现

    public int FirstNotRepeatingChar(String str) {
        if (str == null || str.length() == 0)
            return -1;
        char[] c = str.toCharArray();
        LinkedHashMap<Character,Integer> hash=new LinkedHashMap<Character,Integer>();

        for(char item : c) {
            if(hash.containsKey(item))
                hash.put(item, hash.get(item)+1);
            else
                hash.put(item, 1);
        }

        for(int i = 0;i < str.length(); i++){
            if (hash.get(str.charAt(i)) == 1) {
                return i;
            }
        }
        return -1;
    }

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

思路:本质是归并排序,在比较时加入全局变量count进行记录逆序对的个数,若data[start] >= data[index] ,则count值为mid+1-start

代码实现

    int count = 0;
    public int InversePairs(int [] array) {
        if(array==null)
            return 0;
        mergeSort(array,0,array.length-1);
        return count;
    }

    private void mergeSort(int[] data,int start,int end) {
        int mid = (start + end) / 2;
        if (start < end) {
            mergeSort(data, start, mid);
            mergeSort(data, mid + 1, end);
            merge(data, start, mid, end);
        }
    }

    public void merge(int[] data,int start,int mid,int end) {
        int arr[] = new int[end - start + 1];
        int c = 0;
        int s = start;
        int index = mid + 1;
        while (start <= mid && index <= end) {
            if (data[start] < data[index]) {
                arr[c++] = data[start++];
            } else {
                arr[c++] = data[index++];
                count += mid +1 - start;
                count %= 1000000007;
            }
        }

        while (start <= mid) {
            arr[c++] = data[start++];
        }

        while (index <= end) {
            arr[c++] = data[index++];
        }

        for (int d : arr) {
            data[s++] = d;
        }
    }

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

思路:先求出链表长度,然后长的链表先走多出的几步,然后两个链表同时向下走去寻找相同的节点,代码量少的方法需要将两个链表遍历两次,然后从头开始相同的节点。

代码实现

    // 不需要遍历链表的解法
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode p1 = pHead1;
        ListNode p2 = pHead2;
        while (p1 != p2){
            p1 = (p1 != null ? p1.nextNode : pHead2);
            p2 = (p2 != null ? p2.nextNode : pHead1);
        }
        return p1;
    }

38.统计一个数字在排序数组中出现的次数。

思路:利用二分查找+递归思想,进行寻找。当目标值与中间值相等时进行判断

代码实现

    public int GetNumberOfK(int[] array,int k) {
        int result=0;
        int mid = array.length/2;
        
        if(array==null || array.length == 0)
            return 0;
        if(array.length == 1) {
            if(array[0] == k)
                return 1;
            else
                return 0;
        }

        if(k < array[mid])
            result += GetNumberOfK(Arrays.copyOfRange(array, 0, mid),k);
        else if(k > array[mid])
            result += GetNumberOfK(Arrays.copyOfRange(array, mid, array.length),k);
        else {
            for(int i = mid;i < array.length;i++) {
                if(array[i] == k)
                    result++;
                else
                    break;
            }

            for(int i = mid - 1;i >= 0;i--) {
                if(array[i] == k)
                    result++;
                else
                    break;
            }
        }

        return result;
    }

39.输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

思路:利用递归遍历分别返回左右子树深度

代码实现

    public int TreeDepth(TreeNode root) {
        if (root == null)
            return 0;

        int left = TreeDepth(root.left);
        int right = TreeDepth(root.right);
        return left > right ? left + 1 : right + 1;
    }

39.1输入一棵二叉树,判断该二叉树是否是平衡二叉树。

思路:平衡因子的绝对值<= 1.

代码实现

    public boolean isBalanced(TreeNode root) {
	   if(root == null) {
	       return true;
	   }
	   boolean condition = Math.abs(maxDepth(root.left) - maxDepth(root.right)) <= 1;
	   return condition && isBalanced(root.left) && isBalanced(root.right);
    }

    public int treePath(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int left = treePath(root.left);
        int right = treePath(root.right);
        return left > right ? (left + 1) : (right + 1);
    }

40.一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

思路:两个相同的数异或后为0,将所有数异或后得到一个数,然后求得1在该数最右边出现的index,然后判断每个数右移index后是不是1。

代码实现

    public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
        if (array == null)
            return;
        num1[0] = 0;
        num2[0] = 0;
        int number = array[0];
        for (int i = 1; i < array.length; i++)
            number ^= array[i];
        // 异或后的数1出现在第几位
        int index = 0;
        while ((number & 1) == 0) {
            number = number >> 1;
            index++;
        }

        for (int i = 0; i < array.length; i++) {
            // 判断第index位是不是0
            boolean isBit = ((array[i] >> index) & 1) == 0;
            if (isBit) {
                num1[0] ^= array[i];
            } else {
                num2[0] ^= array[i];
            }
        }
    }

未完待续。。。。。。

你可能感兴趣的:(面试)