《剑指offer第二版》十一

1. 左旋转字符串

(1)题目描述

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”

(2)题目分析

将字符串的前半段拿出来,拼接到后半段即可。

(3)代码

package swordOffer.day11;

/**
 * @author chengzhengda
 * @version 1.0
 * @date 2020-04-12 11:07
 * @desc
 */
public class t53 {
    public static String reverseLeftWords(String s, int n) {
        return s.substring(n) + s.substring(0, n);
    }

    public static void main(String[] args) {
        System.out.println(reverseLeftWords("dadahaha", 4));
    }
}

2. 翻转单词顺序

(1)题目描述

输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。

示例 1:
输入: “the sky is blue”
输出: “blue is sky the”

(2)题目分析

将字符串分割,然后反向拼接即可。

(3)代码

package swordOffer.day11;

/**
 * @author chengzhengda
 * @version 1.0
 * @date 2020-04-11 18:27
 * @desc
 */
public class t52 {
    public static String reverseWords(String s) {

        String[] strs = s.trim().split(" ");
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = strs.length - 1; i > 0; i--) {
            if ("".equals(strs[i].trim())) {
                continue;
            }
            stringBuilder.append(strs[i].trim()).append(" ");
        }
        stringBuilder.append(strs[0]);
        return stringBuilder.toString();
    }

    public static void main(String[] args) {
        String str = "    ";
        System.out.println(reverseWords(str));
    }
}

3. 不用加减乘除做加法

(1)题目描述

写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
示例:
输入: a = 1, b = 1
输出: 2

(2)题目分析

两数相加,其实就是二进制的每一位上的数字之和,再加上进位,每位上的数字之和可以表示为a^b,而进位则可以表示为(a&b)<<1,通过迭代与循环,直到进位为0,则a^b的结果即为所求。

(3)代码

package swordOffer.day11;

/**
 * @author chengzhengda
 * @version 1.0
 * @date 2020-04-12 11:22
 * @desc
 */
public class t54 {
    public static int add(int a, int b) {
        while (a != 0) {
            int temp = a ^ b;
            a = (a & b) << 1;
            b = temp;
        }
        return b;
    }

    public static void main(String[] args) {
        System.out.println(add(13, 9));
    }
}

4. 1~n整数中1出现的次数

(1)题目描述

输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。
例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。

示例 1:
输入:n = 12
输出:5

(2)题目分析

本题可利用动态规划的思想进行求解,需要分2种情况进行分析。假设f(n)为所求的结果,当最高位为1时,f(n) = f(pow-1) + last +1 + f(last),其中pow为数字的最大单位,如果数字有4位,则pow = 1000,last为n-pow的值,当最高位不为1时,f(n) =high* f(pow-1) + f(last) + pow,其中high为最高位的数字。

(3)代码

package swordOffer.day11;

/**
 * @author chengzhengda
 * @version 1.0
 * @date 2020-04-12 15:30
 * @desc
 */
public class t55 {
    public static int countDigitOne(int n) {
        if (n <= 0) {
            return 0;
        }
        String str = String.valueOf(n);
        int high = str.charAt(0) - '0';
        int pow = (int) Math.pow(10, str.length() - 1);
        int last = n % pow;
        if (high == 1) {
            return countDigitOne(pow - 1) + countDigitOne(last) + last + 1;
        }
        return high * countDigitOne(pow - 1) + pow + countDigitOne(last);

    }

    public static void main(String[] args) {
        System.out.println(countDigitOne(100));
    }
}

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

(1)题目描述

数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。
请写一个函数,求任意第n位对应的数字。
示例 1:
输入:n = 3
输出:3

(2)题目分析

本题通过找规律的方法,可以发现1位的数字有10个,2位的数字有90个,3位的数字有900个,4位的数字有2700个…,即f(n) = 9 * 10 ^ (n-1),n为序列中数字的位数。那么我们就能求出每一种位数的数字所占总数字的字符数之和.

(3)代码

package swordOffer.day11;

/**
 * @author chengzhengda
 * @version 1.0
 * @date 2020-04-12 15:46
 * @desc
 */
public class t60 {
    public static int findNthDigit(int n) {
        if (n < 10) {
            return n;
        }
        int base = 1;
        long count = 0;  //计算有多少位,测试的时候发现有个1e9的用例,这个用例会导致count越界
        while (true) {
            count = helper(base);
            if (n < count) break;
            n -= count;
            base++;
        }
        //得到新的n和count了,算出第n位对应什么数字
        int num = (int) (n / base + Math.pow(10, base - 1));
        return String.valueOf(num).charAt(n % base) - '0';
    }

    // 计算当前有多少位 1位数10种,10位;2位数 90个数字 180位;3位数 900个 2700位
    private static long helper(int base) {
        if (base == 1) {
            return 10;
        }
        return (long) (Math.pow(10, base - 1) * 9 * base);
    }

    public static void main(String[] args) {
        System.out.println(findNthDigit(12));
    }
}

6. 二叉搜索树的最近公共祖先

(1)题目描述

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
《剑指offer第二版》十一_第1张图片
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。

(2)题目分析

由于二叉树的特性,本题通过递归即可求解。如果p和q节点的值均大于root,则p,q一定在root的右子树,如果p和q节点的值均小于root,则p,q一定在root的左子树,否则p,q则为root的左右节点。

(3)代码

package swordOffer.day11;

import leetcode.week2.TreeNode;

/**
 * @author chengzhengda
 * @version 1.0
 * @date 2020-04-12 16:34
 * @desc
 */
public class t61 {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) {
            return null;
        }
        if (p.data < root.data && q.data < root.data) {
            return lowestCommonAncestor(root.left, p, q);
        }
        if (p.data > root.data && q.data > root.data) {
            return lowestCommonAncestor(root.right, p, q);
        }
        return root;
    }
}

7. 二叉树的最近公共祖先

(1)题目描述

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉树: root = [3,5,1,6,2,0,8,null,null,7,4]
《剑指offer第二版》十一_第2张图片
示例 1:
输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出: 3
解释: 节点 5 和节点 1 的最近公共祖先是节点 3。

(2)题目分析

本题与上题的解法类似,由于失去了二叉搜索树的特性,这里通过递归求解,如果p,q不在root的左子树,则肯定在二叉树的右子树,如果不在二叉树的右子树,则肯定在左子树,如果同时存在于左右子树,则p,q的最近公共祖先一定是root。

(3)代码

package swordOffer.day11;

import leetcode.week2.TreeNode;

/**
 * @author chengzhengda
 * @version 1.0
 * @date 2020-04-12 21:42
 * @desc
 */
public class t62 {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null || root == p || root == q) {
            return root;
        }
        TreeNode leftNode = lowestCommonAncestor(root.left, p, q);
        TreeNode rightNode = lowestCommonAncestor(root.right, p, q);
        if (leftNode == null) {
            return rightNode;
        }

        if (rightNode == null) {
            return leftNode;
        }
        return root;
    }

你可能感兴趣的:(剑指offer第二版)