剑指Offer-68道面试题(31-40题)-Java实现

31. 1-n 整数中1出现的次数 – 时间效率

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

public class Solution {
    public int NumberOf1Between1AndN_Solution(int n) {
        int count =0;
        for (int i = 1; i <= n; i++) {
            String str = String.valueOf(i);
            if(str.contains("1")){
                for (int j = 0; j < str.length(); j++) {
                    if(str.charAt(j)=='1'){
                        count++;
                    }
                }
            }
        }
        return count;
    }
}
32. 把数组排成最小的数 – 时间效率

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

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

public class Solution {
    public String PrintMinNumber(int[] numbers) {
        ArrayList<String> str = new ArrayList<String>();
        for (int i = 0; i < numbers.length; i++) {
            str.add(String.valueOf(numbers[i]));
        }
        /*
         * a,b 
         * ab<ba,a<b
         * ab>ba,a>b
         */
        Collections.sort(str, new Comparator<String>() {
            public int compare(String str1, String str2) {
                String s1 = str1 + str2;
                String s2 = str2 + str1;
                return s1.compareTo(s2);
            }
        });
        StringBuilder sb = new StringBuilder();
        for (String string : str) {
            sb.append(string);
        }
        return sb.toString();
    }
}
33. 丑数 – 时间效率与空间效率的平衡

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

import java.util.LinkedList;
public class Solution {
    public int GetUglyNumber_Solution(int index) {
        /**
         * 首先,丑数不断除以2 or 3 or 5 最后等于1
         * 前15个丑数,1,2,3,4,5,6,8,9,10,12,15,16,18,20,24... 
         * 1*2,1*3,1*5,
         * 2*2,2*3,2*5,...,3*2,3*3,3*5 
         * 类似于打表,但是要注意顺序
         */
        if (index < 7) {
            return index;
        }
        LinkedList<Integer> list = new LinkedList<Integer>();
        int num = 1;
        list.add(num);
        // 三个指针
        int a = 0;
        int b = 0;
        int c = 0;
        while (list.size() < index) {
            num = Math.min(Math.min(list.get(a) * 2, list.get(b) * 3),
                    list.get(c) * 5);
            if (num == list.get(a) * 2)
                a++;
            if (num == list.get(b) * 3)
                b++;
            if (num == list.get(c) * 5)
                c++;
            list.add(num);
        }
        return num;
    }
}
34. 第一个只出现一次的字符位置 – 时间效率与空间效率的平衡

题目描述
在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)

public class Solution {
    public int FirstNotRepeatingChar(String str) {
        int[] hashtable = new int[26 + 26 + 6];
        for (int i = 0; i < str.length(); i++) {
            hashtable[str.charAt(i) - 'A']++;
        }
        for (int i = 0; i < str.length(); i++) {
            if (hashtable[str.charAt(i) - 'A'] == 1) {
                return i;
            }
        }
        return -1;
    }
}
35. 数组中的逆序对 – 时间效率与空间效率的平衡

题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。
即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字数据范围: 对于%50的数据,size<=10^4 对于%75的数据,size<=10^5 对于%100的数据,size<=2*10^5
示例1
输入
1,2,3,4,5,6,7,0
输出
7

public class Solution {
    public int InversePairs(int[] array) {
        if (array == null || array.length == 0) {
            return 0;
        }
        int[] copy = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            copy[i] = array[i];
        }
        int count = InversePairsCore(array, copy, 0, array.length - 1) % 1000000007;// 数值过大求余
        return count;
    }        
    private int InversePairsCore(int[] array, int[] copy, int low, int high) {
        if (low == high) {
            return 0;
        }
        int mid = (low + high) >> 1;
        int leftCount = InversePairsCore(array, copy, low, mid) % 1000000007;
        int rightCount = InversePairsCore(array, copy, mid + 1, high) % 1000000007;
        int count = 0;
        int i = mid;
        int j = high;
        int locCopy = high;
        while (i >= low && j > mid) {
            if (array[i] > array[j]) {
                count += j - mid;
                copy[locCopy--] = array[i--];
                if (count >= 1000000007)// 数值过大求余
                {
                    count %= 1000000007;
                }
            } else {
                copy[locCopy--] = array[j--];
            }
        }
        for (; i >= low; i--) {
            copy[locCopy--] = array[i];
        }
        for (; j > mid; j--) {
            copy[locCopy--] = array[j];
        }
        for (int s = low; s <= high; s++) {
            array[s] = copy[s];
        }
        return (leftCount + rightCount + count) % 1000000007;
    }
}
36. 两个链表的第一个公共结点 – 时间效率与空间效率的平衡

题目描述
输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

/*
public class ListNode {
    int val;
    ListNode next = null;
    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public static ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if (pHead1 == null || pHead2 == null) {
            return null;
        }
        // 计算长度差
        int len1 = 1, len2 = 1;
        ListNode pNode1 = pHead1;
        ListNode pNode2 = pHead2;
        while ((pNode1 = pNode1.next) != null) {
            len1++;
        }
        while ((pNode2 = pNode2.next) != null) {
            len2++;
        }
        if (len1 > len2) {
            int n = len1 - len2;
            while (n > 0) {
                pHead1 = pHead1.next;
                n--;
            }
        } else {
            int n = len2 - len1;
            while (n > 0) {
                pHead2 = pHead2.next;
                n--;
            }
        }
        ListNode result = new ListNode(0);
        boolean flag = true;
        while (pHead1 != null) {
            if (pHead1.val == pHead2.val && flag) {
                result = pHead1;
                // System.out.println(result.val);
                flag = false;
            } else if (pHead1 != pHead2) {
                result = null;
                // 可以重新给结果赋值
                flag = true;
            }
            pHead1 = pHead1.next;
            pHead2 = pHead2.next;
        }
        return result;
    }
}
// 看到一个大佬的写法,画个图理解一下
/*两个链表 6,5,4,3,2,1;	5,4,2,2,1
6 5 4 3          5 4 2 2 1
        2 1 null 
  5 4 2          6 5 4 3 2 1
*/
public class Solution {
    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode p1 = pHead1;
        ListNode p2 = pHead2;
        while (p1 != p2) {
            p1 = p1 == null ? pHead2 : p1.next;
            p2 = p2 == null ? pHead1 : p2.next;
        }
        return p1;
    }
}
37. 数字在排序数组中出现的次数 – 知识迁移能力

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

public class Solution {
    public int GetNumberOfK(int[] array, int k) {
        int number = 0;
        int len = array.length;
        // 有序数组,二分查找
        if (array != null && len > 0) {
            int first = GetFirstK(array, k, 0, len - 1);
            int last = GetLastK(array, k, 0, len - 1);
            if (first > -1 && last > -1) {
                // System.out.println(last+"  "+first);
                number = last - first + 1;
            }
        }
        return number;
    }
    
    public int GetFirstK(int[] array, int k, int start, int end) {
        if (start > end) {
            return -1;
        }
        int middle = (start + end) / 2;
        int middledata = array[middle];
        if (middledata == k) {
            if (middle > 0 && array[middle - 1] < k || middle == 0) {
                return middle;
            } else {
                end = middle - 1;
            }
        } else if (middledata > k) {
            end = middle - 1;
        } else {
            start = middle + 1;
        }
        return GetFirstK(array, k, start, end);
    }
    
    public int GetLastK(int[] array, int k, int start, int end) {
        if (start > end) {
            return -1;
        }
        int middle = (start + end) / 2;
        int middledata = array[middle];
        while (start <= end) {
            if (middledata == k) {
                if (middle < array.length - 1 && array[middle + 1] != k
                        || middle == array.length - 1) {
                    return middle;
                } else {
                    start = middle + 1;
                }
            } else if (middledata < k) {
                start = middle + 1;
            } else {
                end = middle - 1;
            }
            middle = (start + end) / 2;
            middledata = array[middle];
        }
        return -1;
    }
}
38. 二叉树的深度 – 知识迁移能力

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

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;
    public TreeNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    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. 平衡二叉树 – 知识迁移能力

题目描述
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树

public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        return getDepth(root) != -1;
    }
    
    private int getDepth(TreeNode root) {
        if (root == null)
            return 0;
        // 后序遍历
        int left = getDepth(root.left);
        if (left == -1)
            return -1;
        int right = getDepth(root.right);
        if (right == -1)
            return -1;
        return Math.abs(left - right) > 1 ? -1 : 1 + Math.max(left, right);
    }
}
40. 数组中只出现一次的数字 – 知识迁移能力

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

//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
public class Solution {
    public void FindNumsAppearOnce(int[] array, int[] num1, int[] num2) {
        int length = array.length;
        if (length < 2) {
            return;
        }
        int bitResult = 0;
        for (int i = 0; i < length; ++i) {
            bitResult ^= array[i];
        }
        int index = findFirst1(bitResult);
        num1[0] = 0;
        num2[0] = 0;
        for (int i = 0; i < length; ++i) {
            if (isBit1(array[i], index)) {
                num1[0] ^= array[i];
            } else {
                num2[0] ^= array[i];
            }
        }
    }
    
    private int findFirst1(int bitResult) {
        int index = 0;
        while (((bitResult & 1) == 0) && index < 32) {
            bitResult = bitResult >> 1;
            index++;
        }
        return index;
    }
    
    private boolean isBit1(int target, int index) {
        target = target >> index;
        return (target & 1) == 1;
    }
}

其他题目

→→点击跳转

猜你喜欢

转载自blog.csdn.net/weixin_43845524/article/details/106113050