剑指offer刷题笔记(三)

剑指offer刷题笔记(三)


面试题16. 数值的整数次方
  • 实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。
示例 1:
输入: 2.00000, 10
输出: 1024.00000
示例 2:
输入: 2.10000, 3
输出: 9.26100
示例 3:
输入: 2.00000, -2
输出: 0.25000
解释: 2-2 = 1/22 = 1/4 = 0.25
  • 说明:
-100.0 < x < 100.0
n 是 32 位有符号整数,其数值范围是 [−231, 231 − 1] 。

思路:
这个问题主要解决还是时间复杂度,我们需要了解计算机中加减运算的原理,,用右移运算符代替除以二,用位与运算符&代替求余操作在效率上会高很多.另外,在求一个数的整数次方,例如2的32次方时,我们可以将其替换成2的16次方的平方,进而2的8次的平方,用递归来实现这一操作.

class Solution {
    public double myPow(double x, int n) {
        if(x==0.0&&n<0){
            return 0;
        }
        long i=n;
        if(n<0){
            i=-(long)n;
        }
        double result=powerResult(x,i);
        if(n<0){
            result=1/result;
        }
        return result;
    }
    public double powerResult(double x,long n){
        if(n==0){
            return 1;
        }
        if(n==1){
            return x;
        }
        double result=powerResult(x,n>>1);
        result*=result;
        if((n&1)==1){
            result*=x;
        }
        return result;
    }
}

面试题17. 打印从1到最大的n位数

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]

说明:

用返回一个整数列表来代替打印
n 为正整数

这种方法是最容易想到的方法,但没有考虑到大数问题.

class Solution {
    public int[] printNumbers(int n) {
        double max = Math.pow(10, n);
        int len = (int) max-1;
        int [] res = new int [len];
        for(int i=0;i

part2: 考虑到大数问题,用字符数组来存储得到的结果.如果我们在结果数组前面补0,就会发现其实就是数字从0-9的全排列问题,打印时0不打印即可

class Solution {
    public void printNumbers(int n) {
        char[] a=new char[n+1];
        if(n<=0){
            return;
        }
        a[n]='\0';
        for(int i=0;i<10;i++){
            a[0]=(char)('0'+i);
            prints(a,n,0);
        }
    }
    public void prints(char[] a,int length,int index){
        if(index==length-1){
            printa(a);
            return;
        }
        for(int i=0;i<10;i++){
            a[index+1]=(char)(i+'0');
            prints(a,length,index+1);
        }
    }
    public void printa(char[] a){
        boolean isbeginning=true;
        for(int i=0;i

面试题19. 正则表达式匹配

请实现一个函数用来匹配包含'. '和''的正则表达式。模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"ab*a"均不匹配。

输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
输入:
s = "aa"
p = "a*"
输出: true
解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
输入:
s = "aab"
p = "c*a*b"
输出: true
解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
输入:
s = "mississippi"
p = "mis*is*p*."
输出: false

s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母以及字符 . 和 '*',无连续的 0'*'。

分析字符串,当模式字符串中字符是'.'时,可以匹配任意一个字符,如果不是‘.’,而且匹配串中的字符也跟他相互匹配,也往下走,最复杂的情况是'',碰见''时,一种选时模式串往后两个字符,相当于被忽略,一种是字符串向后移动一个字符,这时模式串可以向后移动两个字符,也可以不移动。我第一次提交时将两种情况都包含进去,后来发现超时了,看了题解中的解释才明白,字符串向后移动欧诺个,模式串可以不移动,因为模式串向后移动两个字符已经被包括在第一次的选择中了,相当于我们进行了重复操作。

public class test {
    public static void main(String[] args) {


        String s="aaaaaaaaaaaaab";
        String p="a*a*a*a*a*a*a*a*a*a*c";
        Solution a=new Solution();
        System.out.println(a.isMatch(s,p));
    }
}
class Solution {
    public boolean isMatch(String s, String p) {
        if (s.length() == 0) {
            if (p.length() % 2 != 0) {
                return false;
            }
            int i = 1;
            while (i < p.length()) {
                if (p.charAt(i) != '*') {
                    return false;
                }
                i += 2;
            }
            return true;
        }
        if(p.length()==0){
            return false;
        }
        char a1 = s.charAt(0);
        char a2 = p.charAt(0);
        char a3 = 'a';
        if (p.length() > 1) {
            a3 = p.charAt(1);
        }
        if (a3 == '*') {
            if (a1 == a2 || a2 == '.') {
                
                return isMatch(s.substring(1), p)||isMatch(s,p.substring(2));
            } else {
                return isMatch(s, p.substring(2));
            }
        }
        if (a1 == a2 || a2 == '.') {
            return isMatch(s.substring(1), p.substring(1));
        }
        return false;
    }
}


面试题20. 表示数值的字符串

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100"、"5e2"、"-123"、"3.1416"、"0123"都表示数值,但"12e"、"1a3.14"、"1.2.3"、"+-5"、"-1E-16"及"12e+5.4"都不是。

class Solution {
    public boolean isNumber(String s) {
        if(s==null||s.length()==0){
            return false;
        }
        boolean numbool=false;
        boolean dotbool=false;
        boolean ebool=false;
        char[] a=s.trim().toCharArray();
        for(int i=0;i='0'&&a[i]<='9'){
                numbool=true;
            }
            else if(a[i]=='.'){
                if(dotbool||ebool){
                    return false;
                }
                else{
                    dotbool=true;
                }
            }
            else if(a[i]=='e'||a[i]=='E'){
                if(!numbool||ebool){
                    return false;
                }
                else{
                    ebool=true;
                    numbool=false;
                }
            }
            else if(a[i]=='+'||a[i]=='-'){
                if(i!=0&&a[i-1]!='e'&&a[i-1]!='E'){
                    return false;
                }
            }
            else{
                return false;
            }
        }
        return numbool;
    }
}


面试题21. 调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。

用位与运算符来代替求余操作,剩下就是两头遍历交换了。

class Solution {
    public int[] exchange(int[] nums) {
        if(nums==null||nums.length==0){
            return nums;
        }
        int i=0;
        int j=nums.length-1;
        while(i

面试题22. 链表中倒数第k个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。例如,一个链表有6个节点,从头节点开始,它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个节点是值为4的节点。

给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.

这题的思路其实算是个经典了,网上也很多,就是讲第一个指针先移动,然后两个指针同时移动即可。这题更需要关注的其实是对空列表的处理,为了防止程序崩溃,代码中多出加入对空的处理

class Solution {
    public ListNode getKthFromEnd(ListNode head, int k) {
        if(head==null||k==0){
            return null;
        }
        ListNode aListNode=head;
        ListNode bListNode=head;
        for(int i=0;i

面试题24. 反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL

在反转过程中为了防止链表断链而导致的数据丢失,我们需要先将断链后的结果存储起来。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode headNode=head;
        ListNode preNode=null;
        ListNode reserveNode=null;
        while(headNode!=null){
            ListNode nextNode=headNode.next;
            if(nextNode==null){
                reserveNode=headNode;
            }
            headNode.next=preNode;
            preNode=headNode;
            headNode=nextNode;
        }
        return reserveNode;
    }
}

面试题25. 合并两个排序的链表

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

思路就是递归操作,更多的需要注意非法输入和空链表的判断。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1==null){
            return l2;
        }
        if(l2==null){
            return l1;
        }
        ListNode l=null;
        if(l1.val

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