剑指offer刷题笔记(六)

剑指offer刷题笔记(六)


剑指 Offer 42. 连续子数组的最大和
  • 输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
    要求时间复杂度为O(n)。
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

贪心法,当相加和为负数而当前数组值为正数时,我们就可以抛弃之前的和,从这个数组重新开始。

class Solution {
    public int maxSubArray(int[] nums) {
        if(nums.length==0){
            return 0;
        }
        int sum=0;
        int maxsum=Integer.MIN_VALUE;
        for(int i=0;imaxsum){
                maxsum=sum;
            }
        }
        return maxsum;
    }
}

动态规划版本

class Solution {
    public int maxSubArray(int[] nums) {
        if (nums.length == 0 ) return 0;
        int[] dp = new int[nums.length ];
        dp[0] = nums[0];
        int max = dp[0];
        for (int i = 1; i < dp.length; i++) {
            if (dp[i-1] > 0) {
                dp[i] = dp[i-1] + nums[i];
            }else {
                dp[i] = nums[i];
            }
            max = Math.max(max, dp[i]);
        }
        return max;
    }
}

剑指 Offer 43. 1~n整数中1出现的次数
  • 输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
    例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。
示例 1:
输入:n = 12
输出:5
示例 2:
输入:n = 13
输出:6
class Solution {
    public int countDigitOne(int n) {
        return count(n);
    }
    public int count(int n){
        if(n<=0){
            return 0;
        }
        String s=String.valueOf(n);
        int high=s.charAt(0)-'0';//层数
        int pow=(int)Math.pow(10,s.length()-1);//
        int last=n-high*pow;
        if(high==1){
            return last+1+count(pow-1)+count(last);
        }
        else{
            return high*count(pow-1)+count(last)+pow;
        }
    }
}

剑指 Offer 44. 数字序列中某一位的数字
  • 数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。
    请写一个函数,求任意第n位对应的数字。
示例 1:
输入:n = 3
输出:3
示例 2:
输入:n = 11
输出:0
class Solution {
    public int findNthDigit(int n) {
        if(n<0){
            return -1;
        }
        if(n<=9){
            return n;
        }
        int digt=1;
        while(n>0.9*Math.pow(10,digt)*digt){
        //获得几位数,以及获得在基准值上的偏移量
            n-=0.9*Math.pow(10,digt)*digt;
            digt++;
        }
        //获得基准值,偏移量除以位数。获得取到哪个数
        int begin=(int)Math.pow(10,digt-1)+(n-1)/digt;
        String s=String.valueOf(begin);
        //偏移量取余,获得第几个字符
        int i=(n-1)%digt;
        return s.charAt(i)-'0';
    }
}

剑指 Offer 45. 把数组排成最小的数
  • 输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
示例 1:
输入: [10,2]
输出: "102"
示例 2:
输入: [3,30,34,5,9]
输出: "3033459"

注意大数问题,用字符串保存。自己构建一个比较器,来对比两个字符的拼接谁大。

class Solution {
    public String minNumber(int[] nums) {
        List list=new ArrayList<>();
        for (int num:nums
             ) {
            list.add(String.valueOf(num));
        }
        list.sort((s1,s2)->(s1+s2).compareTo(s2+s1));
        StringBuilder builder=new StringBuilder();
        for (String s:list
             ) {
            builder.append(s);
        }
        return builder.toString();
    }
}

题解处的stream流 写法。搬运一下 测试了一下,上一种耗时9ms,这种耗时18ms。作为知识储备吧。

class Solution {
    public String minNumber(int[] nums) {
        return Arrays.stream(nums)
                .boxed()
                .map(String::valueOf)
                .sorted((s1,s2)->(s1+s2).compareTo(s2+s1))
                .collect(Collectors.joining());
    }
}
剑指 Offer 46. 把数字翻译成字符串
  • 给定一个数字,我们按照如下规则把它翻译为字符串:
    0 翻译成 “a” ,
    1 翻译成 “b”,……,
    11 翻译成 “l”,……,
    25 翻译成 “z”。
    一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:

输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"

与青蛙跳台阶问题类似,动态规划解决,多出一步去掉一个无法翻译的情况就行。

class Solution {
    public int translateNum(int num) {
        if(num<0){
            return 0;
        }
        String s=String.valueOf(num);
        int a=1;
        int b=1;
        for(int i=2;i<=s.length();i++){
            String tmp=s.substring(i-2,i);
            int c = tmp.compareTo("10") >= 0 && tmp.compareTo("25") <= 0 ? a + b : a;
            b=a;
            a=c;
        }
        return a;
    }
}

剑指 Offer 47. 礼物的最大价值
  • 在一个 m*n 的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于 0)。
    你可以从棋盘的左上角开始拿格子里的礼物,并每次向右或者向下移动一格、直到到达棋盘的右下角。给定一个棋盘及其上面的礼物的价值,请计算你最多能拿到多少价值的礼物?
示例 1:

输入: 
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
输出: 12

dp动态规划,grid[i][j]=max(grid[i-1][j],grid[i][j-1])+grid[i][j]),同时为了优化效率,率先初始化第一行和第一列

class Solution {
    public int maxValue(int[][] grid) {
        if(grid.length==0){
            return 0;
        }
        int m=grid.length;
        int n=grid[0].length;
        for(int j=1;j

剑指 Offer 48. 最长不含重复字符的子字符串
  • 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例 1:

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:

输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例 3:

输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
     请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。

动态规划

class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s.length()==0){
            return 0;
        }
        Map str=new HashMap<>();
        int res=0;
        int tmp=0;
        for(int i=0;i

剑指 Offer 49. 丑数
  • 我们把只包含质因子 2、3 和 5 的数称作丑数(Ugly Number)。求按从小到大的顺序的第 n 个丑数。
示例:

输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。
说明:  

1 是丑数。
n 不超过1690。

动态规划 找到一个丑数的2倍,3倍或者5倍的最小值大于当前最大丑数,就是下一个丑数。

class Solution {
    public int nthUglyNumber(int n) {
        if(n==0){
            return 0;
        }
        int[] x=new int[n];
        int next=1;
        x[0]=1;
        int x2=0;
        int x3=0;
        int x5=0;
        while(next

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

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

s = "abaccdeff"
返回 "b"
s = "" 
返回 " "

这是我率先想到的思路,用哈希表存储,有重复字符串则次数加一

class Solution {
    public char firstUniqChar(String s) {
        if(s.equals("")
        ){
            return ' ';
        }
        Map str=new HashMap<>();
        char[] x=s.toCharArray();
        for (char p:x) {
            if(str.get(p)!=null){
                str.put(p,str.get(p)+1);
            }
            else{
                str.put(p,1);
            }
        }
        for (char key:x) {
            if(str.get(key)==1){
                return key;
            }
        }
        return ' ';

    }
}

题解区大佬做法,用数组代替哈希表,在确定容量的情况下更加高速,耗时4ms,上一种36ms

class Solution {
    public char firstUniqChar(String s) {
        int[] count = new int[256];
        char[] chars = s.toCharArray();
        for(char c : chars)
            count[c]++;
        for(char c : chars){
            if(count[c] == 1)
                return c;
        }
        return ' ';
    }
}

作者:ustcyyw
链接:https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/solution/mian-shi-ti-50java-shi-yong-shu-zu-dai-ti-ha-xi-bi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

剑指 Offer 51. 数组中的逆序对
  • 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5

归并排序,在合并时计算逆序对的数量。

class Solution {
    public int reversePairs(int[] nums) {
        if(nums.length<2){
            return 0;
        }
        int[] copy=new int[nums.length];
        int[] tmp=new int[nums.length];
        int count;
        for (int i = 0; i 

剑指 Offer 52. 两个链表的第一个公共节点
  • 输入两个链表,找出它们的第一个公共节点。
    如下面的两个链表:


    image

    在节点 c1 开始相交。
    示例 1:


    image
输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

示例 2:


image
输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

示例 3:


image
输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。
  • 如果两个链表没有交点,返回 null.
  • 在返回结果后,两个链表仍须保持原有的结构。
  • 可假定整个链表结构中没有循环。
  • 程序尽量满足 O(n) 时间复杂度,且仅用 O(1) 内存。

双指针移动,长链表先走几步直到剩余长度与短链表一致。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int xlength=getLength(headA);
        int ylength=getLength(headB);
        ListNode longNode=headA;
        ListNode shortNode=headB;
        int length=xlength-ylength;
        if(xlength

你可能感兴趣的:(剑指offer刷题笔记(六))