Notes6剑指offer_41-68题

Posted 码农编程录

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Notes6剑指offer_41-68题相关的知识,希望对你有一定的参考价值。


41.数据流中的中位数

class MedianFinder {    
    //大根堆 + 小根堆
    //大根堆 堆顶 存的是最大的数字   小的那一半    
    //小根堆 堆顶 存的是最小的数字   大的那一半        
    Queue<Integer> A, B;
    /** initialize your data structure here. */
    public MedianFinder() {
        A = new PriorityQueue<>();//小根堆 存大的一半数字
        B = new PriorityQueue<>((x,y) -> (y - x));//大根堆 存小的一半数字
    }
    
    public void addNum(int num) {
        //无脑放进小根堆
        //如果 小根堆的数字数量 > 大根堆的数字数量了 
        //把小根堆中较小数字 放进大根堆
        if(A.size() != B.size())
        {
            A.add(num);//无脑放进小根堆
            B.add(A.poll());//把小根堆中较小数字 放进大根堆
        }else
        {
            //堆顶比较  确保大小根堆的 一半的特性
            B.add(num);//大数字 在堆顶
            A.add(B.poll());//通过添加堆顶数字 确保 特性
        }
    }    
    public double findMedian() {
        return A.size() == B.size()   (A.peek() + B.peek())/2.0 : A.peek();
    } 
}

42.连续子数组的最大和

class Solution {
    public int maxSubArray(int[] nums) {
        int res = nums[0];//最大子数组的和
        
        for(int i = 1; i < nums.length; i ++){
            //动态规划
            //dp[i]到i位置 最大子数组的和
            //dp[i - 1]  nums[i]
            nums[i] += Math.max(nums[i - 1], 0);
            res = Math.max(res, nums[i]);
        }
        
        return res;
    }
}

43.1~n整数中1出现的次数

class Solution {
    public int countDigitOne(int n) {
        //high cur low
        //4507
        // cur == 0  high * 10^i
        //high 45 cur 0 low 7
        // 4507     
        // 0010 - 4419
        // 000 - 449  450个数字
        //cur == 1 high* 10^i  + low + 1
        //4517
        //high 45  cur 1 low 7
        //0010 4517
        //000 - 457   458个数字
        //cur == 2 3 4...9   (high+1) * 10^i
        //4527
        //high 45  cur 2 low 7
        // 0010 - 4519
        // 000 - 459  460个数字
        int x = 1, res = 0;
        int high = n / 10, cur = n % 10, low = 0;
        while(high != 0 || cur != 0){ 
            if(cur == 0) res += high * x;
            else if(cur == 1) res += high * x + low + 1;
            else res += (high + 1) * x;
            low += cur * x;
            cur = high % 10;
            high /= 10;
            x *= 10;
        }
        return res;
    }
}

44.数字序列中某一位的数字

class Solution {
    public int findNthDigit(int n) {
        //第一步 确定n在哪个 数位的数中  1  2  3
        //1 9
        //10 99
        //100 999
        int digit = 1;
        long start = 1;
        long count = 9;
        while(n > count){//得到了digit
            n -= count;
            digit += 1;
            start *= 10;
            count = digit * start * 9;//对于 2 个数字组成的10- 99  180  2*90
        }
        //第二步:确定在哪个数字中 15
        long num = start + (n - 1)/digit;
        //第三步:找到确定的1位的数字
        return Long.toString(num).charAt((n - 1) % digit) - '0';
    }
}

45.把数组排成最小的数

class Solution {
    public String minNumber(int[] nums) {
        String[] str = new String[nums.length];
        for(int i = 0; i < nums.length; i ++){
            str[i] = String.valueOf(nums[i]);
        }
        //字符串排序
        strsort(str, 0, str.length - 1);//快排
        //Arrays.sort(str,(x,y) -> (x + y).compareTo(y + x));//内置函数
        //字符串数组依次组合
        StringBuilder res = new StringBuilder();
        for(String s : str){
            res.append(s);
        }
        return res.toString();
    }
    void strsort(String[] str, int l, int r){
        //快排写法
        if(l >= r) return;
        int i = l, j = r;
        String temp = str[i];
        while(i < j){
            while((str[j] + str[l]).compareTo(str[l] + str[j]) >= 0 && i < j) j --;
            while((str[i] + str[l]).compareTo(str[l] + str[i]) <= 0 && i < j) i ++;
            temp = str[i];
            str[i] = str[j];
            str[j] = temp;
        }
        str[i] = str[l];
        str[l] = temp;
        strsort(str, l, i - 1);
        strsort(str, i + 1, r);
    }
}

46.把数字翻译成字符串

class Solution {
    public int translateNum(int num) {
        // 0  ~ 25有意义 
        //dp【i】 = dp【i - 1】 (+ dp【i - 2】)
        String s = String.valueOf(num);
        int a = 1, b = 1;
        for(int i = 2; i <= s.length(); i ++){
            String temp = s.substring(i - 2, i);
            int c = temp.compareTo("10") >= 0 && temp.compareTo("25") <= 0   a + b : a;
            b = a;
            a = c;
        }
        return a;
    }
}

47.礼物的最大价值

class Solution {
    public int maxValue(int[][] f) {
        //最经典二维动态规划
        //f[i][j] = max(f[i-1][j], f[i][j - 1])
        int m = f.length, n = f[0].length;
        for(int i = 0; i < m; i ++)
            for(int j = 0; j < n; j ++){
                if(i == 0 && j == 0) continue;
                if(i == 0) f[i][j] += f[i][j - 1];
                else if(j == 0) f[i][j] += f[i - 1][j];
                else f[i][j] += Math.max(f[i - 1][j], f[i][j - 1]);
            }        
        return f[m - 1][n - 1];
    }
}

48.最长不含重复字符的子字符串

class Solution {
    public int lengthOfLongestSubstring(String s) {
        HashMap<Character, Integer> hash = new HashMap<>();
        int res = 0, left = 0;
        for(int i = 0; i < s.length(); i ++){
            char c = s.charAt(i);
            //判断c是否出现过
            //"abcabcbb"
            if(hash.containsKey(c)){
                left = Math.max(left, hash.get(c) + 1);
            }
            hash.put(c, i);
            res = Math.max(res, i - left + 1);
        }
        return res;
    }
}

49.丑数

class Solution {
    public int nthUglyNumber(int n) {
        int[] f = new int[n];//前n个丑数
        int[] pos = new int[3];//对应 2 3 5三个质因子
        f[0] = 1;//第一个丑数1
        for(int i = 1; i < n; i ++)
        {
            int a = f[pos[0]] * 2;
            int b = f[pos[1]] * 3;
            int c = f[pos[2]] * 5;
            int mini = Math.min(Math.min(a, b), c);//一定只包含 2  3 5质因子
            if(f[pos[0]] * 2 == mini) pos[0] ++;//6 2*3  10 2*5
            if(f[pos[1]] * 3 == mini) pos[1] ++;//6 3*2
            if(f[pos[2]] * 5 == mini) pos[2] ++;// 10 5*2
            f[i] = mini;
        }
        return f[n - 1];
    }
}

50.第一个只出现一次的字符

class Solution {
    public char firstUniqChar(String s) {
        ///hash表
        HashMap<Character, Boolean> hash = new HashMap<>();
        char[] ch = s.toCharArray();
        for(char c : ch)
            hash.put(c, !hash.containsKey(c));//先插入 true,如果重复了就变成false
        
        for(char c : ch)
            if(hash.get(c)) return c;
        
        return ' ';
    }
}

51.数组中的逆序对

class Solution {
    //归并排序
    public int reversePairs(int[] nums) {
        int len = nums.length;
        if(len < 2)//逆序对要求两个数字以上
            return 0;
        int[] temp = new int[len];
        return mergeSort(nums, 0, len - 1, temp);
    }
    private int mergeSort(int[] nums, int left, int right, int[] temp){
        //递归终止条件
        if(left >= right)
            return 0;
        int mid = left + (right - left) / 2;//防止溢出
        //[left, mid]
        int leftPairs = mergeSort(nums, left, mid, temp);
        //[mid + 1, right]
        int rightPairs = mergeSort(nums, mid +1, right, temp);
        //[left mid] [mid + 1  right]
        if(nums[mid] <= nums[mid + 1]){
            return leftPairs + rightPairs;
        }
        //跨区间的逆序对
        int crossPairs = mergeSortCross(nums, left, mid, right, temp);
        return leftPairs + rightPairs + crossPairs;
    }
    private int mergeSortCross(int[] nums, int left,int mid, int right, int[] temp){
        for(int i = left; i <= right; i ++)
            temp[i] = nums[i];
        
        int i = left;
        int j = mid + 1;
        //[left i mid]  [mid + 1 j  right]
        // mid - i + 1个逆序对
        int count = 0;
        for(int k = left; k <= right; k ++)以上是关于Notes6剑指offer_41-68题的主要内容,如果未能解决你的问题,请参考以下文章

剑指offer 面试26题

剑指offer 面试32题

剑指offer 面试25题

剑指offer 面试28题

剑指offer 面试18题

剑指offer-25题-复杂链表复制