剑指offer题目实现11~20(java实现)

面试题11:旋转数组的最小数字

java二分查找(实现很重要)

1、什么是二分查找

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

2、二分查找的优缺点是什么?

二分查找(折半查找)算法,是数据结构中一个典型的算法,它的查询速度是非常快的,比较次数少,平均性能好。但是其也有缺点,缺点就是二分查找必须有个前提就是数组是有序的,而且插入删除都比较困难。

3、二分查找的前提:

必须是一个有序的序列。

4、二分查找原理解析(java代码实现)

首先我们定义一个数组

 int[] arr = {11, 22, 33, 44, 55, 66, 77};

二分查找是由两个变量:left索引和right索引控制查询范围,通过不断的折半范围来缩小查询区间实现查询数据。下面通过java语言来实现二分查找。

首先主方法内定义好数组arr,并且定义需要查询的值(这个值可以通过Scanner对象在控制台获取,为了演示我就直接赋值了),然后输出结果。

 public static void main(String[] args) {
    
        int[] arr = {11, 22, 33, 44, 55, 66, 77};
        //定义需要查询的值
        int select_value = 66;
        int index= getIndex(arr,select_value);
        System.out.println("查询值所对应的索引为:" + index);
    }

接下来就是定义一个方法用来实现二分查找了,这里定义了一个有参有返回值的方法getIndex,里面传递了两个参数,一个为数组arr,另一个就是需要查询的值select_value。

public static int getIndex(int[] arr,int select_value) {
 
        //初始化最小值的索引为0
        int left = 0;
        //初始化最大值的索引为arr.length-1
        int right = arr.length - 1;
 
        //首尾相加再除以2得出中间索引
        int mid = (left + right) / 2;
 
        while (left<=right) { //确保程序不会重复查询,不会越界
            if (select_value > arr[mid]) {
                //如果查询的值比中间值大,则往右边区域找,就把最小索引改为中间索引右移一位
                left = mid + 1;
            } else if (select_value < arr[mid]) {
                //如果查询的值比中间值小,则往左边区域找,就把最大索引改为中间索引左移一位
                right = mid - 1;
            } else {
                //剩余的情况就是查询到了结果,那么就直接返回索引。
                return mid;
            }
            mid = (left + right) / 2;
        }
        //没有查询到,则返回-1
        return -1;
    }

java快速排序(实现很重要)

1、快速排序是一种比较高效的排序算法,采用“分而治之”的思想,通过多次比较和交换来实现排序,在一趟排序中把将要排序的数据分成两个独立的部分,对这两部分进行排序使得其中一部分所有数据比另一部分都要小,然后继续递归排序这两部分,最终实现所有数据有序。

优点是效率高,时间复杂度平均为O(nlogn),顾名思义,快速排序是最快的排序算法,耗费的资源少,最佳情况下,空间复杂度为O(logn),每一次都平分数组的情况,代码较为简单。

空间复杂度:好情况就是O(logn),坏情况就是O(n);

2、快速排序图

3、Java 代码实现快速排序

public static void main(String[] args) {
    int[] arry = {9,8,7,6,5,4,3,2,1};
    quickSort(arry,0, arry.length-1);
    System.out.println(Arrays.toString(arry));
}
public static void quickSort(int[] arry,int left,int right){
    //运行判断,如果左边索引大于右边是不合法的,直接return结束次方法
    if(left>right){
        return;
    }
    //定义变量保存基准数
    int base = arry[left];
    //定义变量i,指向最左边
    int i = left;
    //定义j ,指向最右边
    int j = right;
    //当i和j不相遇的时候,再循环中进行检索
    while(i!=j){
        //先由j从右往左检索比基准数小的,如果检索到比基准数小的就停下。
        
        while(arry[j]<=base && i<j){
            j--; //j从右往左检索

        }
        //如果检索到比基准数大的或者相等的就停下
        while(arry[i]>=base && i<j){
            i++; //i从左往右检索
        }
        //代码走到这里i停下,j也停下,然后交换i和j位置的元素
        int tem = arry[i];
        arry[i] = arry[j];
        arry[j] = tem;


    }
    //如果上面while条件不成立就会跳出这个循环,往下执行
    //如果这个条件不成立就说明 i和j相遇了
    //如果i和j相遇了,就交换基准数这个元素和相遇位置的元素
    //把相遇元素的值赋给基准数这个位置的元素
    arry[left] = arry[i];
    //把基准数赋给相遇位置的元素
    arry[i] = base;
    //基准数在这里递归就为了左边的数比它小,右边的数比它大
    //排序基准数的左边
    quickSort(arry,left,i-1);
    //排右边
    quickSort(arry,j+1,right);

}
//将快速排序和堆排序结合
public static void quickSort(List<Integer> items){
    //异常条件检测
    if(items.size() > 1){
        List<Integer> smaller = new ArrayList<>();
        List<Integer> same = new ArrayList<>();
        List<Integer> larger = new ArrayList<>();

        Intger chosenItem = items.get(items.size() / 2);
        for (Integer i : items){
            if(i < chosenItem){
                smaller.add(i);
            } esle if(i > chosenItem){
                large.add(i)
            } else{
                same.add(i);
            }
        }    
        sort(smaller);//Recursive(递归的) call!
        sort(larger);//Recursive(递归的) call!

        items.clear();
        items.addAll(smaller);
        items.addAll(same);
        items.addAlll(larger);    
    }
}
public static void sort(int []ages){
        int oldestAge=100;
        int []timesOfAges=new int[oldestAge];
        
        int len=ages.length;
        for(int i=0;i<len;i++){
            timesOfAges[ages[i]]++;;
        }
 
        //排序
        int index=0;
        for(int i=0;i<oldestAge;i++){
            for(int j=0;j<timesOfAges[i];j++){
                ages[index]=i;
                index++;
            }
        }
    }

import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        
        int left = 0;
        int right = array.length - 1;
        int mid = left;
        
        while(array[left] >= array[right]){
            if(right - left == 1){
                mid = right;
                break;
            } 
            
            mid = (left + right) / 2;
            if(array[mid] >= array[left]){
                left = mid;
            } else if(array[mid] <= array[right]){
                    right = mid;
                }
            } 
        
        return array[mid];
    }
}
import java.util.ArrayList;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        
        int left = 0;
        int right = array.length - 1;
        int mid = left;
        
        while(array[left] >= array[right]){
            if(right - left == 1){
                mid = right;
                break;
            } 
            
            mid = (left + right) / 2;
            //如果下标为 left、right和mid指向的三个数字相等,则只能顺序查找
            if(array[left] == array[right] && array[mid] == array[left]){
                int result = array[left];
                for(int i = left + 1; i <= right; i++){
                    if(result > array[i])
                    result = array[i];
                }
                return result;
            }
            if(array[mid] >= array[left]){
                left = mid;
            } else if(array[mid] <= array[right]){
                    right = mid;
                }
            } 
        
        return array[mid];
    }
}
import java.util.*;
public class Solution {
    public int minNumberInRotateArray(int [] array) {
        //数组一定有元素
        int res = array[0]; 
        //遍历数组
        for(int i = 1; i < array.length; i++) 
            //每次维护最小值
            res = Math.min(res, array[i]); 
        return res;
    }
}

面试题12:矩阵中的路径

回溯法

    public boolean hasPath (char[][] matrix, String word) {
        //字符串转化为字符串数组
        char[] words = word.toCharArray();
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                //从[i,j]这个坐标开始查找
                if (dfs(matrix, words, i, j, 0))
                    return true;
            }
        }
        return false;
    }
boolean dfs(char[][] board, char[] word, int i, int j, int index) {
    if (边界条件的判断) {
        return;
    }

    一些逻辑处理

    boolean res;
    //往右
    res = dfs(board, word, i + 1, j, index + 1)
    //往左
    res |= dfs(board, word, i - 1, j, index + 1)
    //往下
    res |= dfs(board, word, i, j + 1, index + 1)
    //往上
    res |= dfs(board, word, i, j - 1, index + 1)
    //上面4个方向,只要有一个能查找到,就返回true;
    return res;
}

最终的完整代码如下

    public boolean hasPath(char[][] matrix, String word) {
        char[] words = word.toCharArray();
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                //从[i,j]这个坐标开始查找
                if (dfs(matrix, words, i, j, 0))
                    return true;
            }
        }
        return false;
    }

    boolean dfs(char[][] matrix, char[] word, int i, int j, int index) {
        //边界的判断,如果越界直接返回false
        //index表示的是查找到字符串word的第几个字符
        //如果这个字符不等于matrix[i][j],说明验证这个坐标路径是走不通的,直接返回false
        if (i >= matrix.length || i < 0 || j >= matrix[0].length || j < 0 || matrix[i][j] != word[index])
            return false;
        //如果word的每个字符都查找完了,直接返回true
        if (index == word.length - 1)
            return true;
        //把当前坐标的值保存下来,为了在最后复原
        char tmp = matrix[i][j];
        //然后修改当前坐标的值
        //保证不会从进来的方向回去
        matrix[i][j] = '.';
        //走递归,沿着当前坐标的上下左右4个方向查找
        boolean res = dfs(matrix, word, i + 1, j, index + 1)
                || dfs(matrix, word, i - 1, j, index + 1)
                || dfs(matrix, word, i, j + 1, index + 1)
                || dfs(matrix, word, i, j - 1, index + 1);
        //递归之后再把当前的坐标复原
        matrix[i][j] = tmp;
        return res;
    }

时间复杂度:O(mn*k^3),m和n是矩阵的宽和高,最坏的情况下遍历矩阵的所有位置,k是字符串的长度,下面的dfs我们可以把它看做是一棵4叉树,除了第一次的时候可以往4个方向走,其他情况下只能往3个方向走(进来的那个方向回不去)

空间复杂度:O(K),k是字符串的长度

面试题13:机器人的运动范围

threshold,英语单词,名词,意思是“入口;门槛;开始;极限;临界值”。

public class Solution {
    //记录遍历的四个方向
    int[][] dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    //记录答案
    int res = 0;
    
    //计算一个数字的每个数之和
    int cal(int n){
        int sum = 0;
        //连除法算出每一位
        while(n != 0){
            sum += (n % 10);
            n /= 10;
        }
        return sum;
    }

    //深度优先搜索dfs
    void dfs(int i, int j, int rows, int cols, int threshold, boolean[][] vis){
        //boolean[][] vis 用来判断该格子是否已被访问过
        //越界或者已经访问过
        if(i < 0 || i >= rows || j < 0 || j >= cols || vis[i][j] == true)
            return;
        //行列和数字相加大于threshold,不可取
        if(cal(i) + cal(j) > threshold)
            return;
        //满足要求,遍历的格子树+1
        res += 1;
        //标记经过的位置
        vis[i][j] = true;
        //上下左右四个方向搜索
        //int[][] dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        for(int k = 0; k < 4; k++)
            dfs(i + dir[k][0], j + dir[k][1], rows, cols, threshold, vis);
    }

    public int movingCount(int threshold, int rows, int cols) {
        //判断特殊情况
        if(threshold <= 0)
            return 1;
        //标记某个格子没有被访问过
        boolean[][] vis = new boolean[rows][cols];
        dfs(0, 0, rows, cols, threshold, vis);
        return res;
    }
}

java求任意数字的位数之和

import java.util.Scanner;
/**
 * 用JAVA求任意一个数的各个位数之和
 * @author Administrator
 *
 */
public class test {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.print("请输入一个数字:");
        int num = sc.nextInt();
        int sum=0;
        while(num!=0){
            sum = sum + num%10;
            num = num/10;
        }
        System.out.println("所给数字的各个位数之和为:"+sum);        
    } 
}
import java.util.*;
public class Solution {
    //记录遍历的四个方向
    int[][] dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    //记录答案
    int res = 0;
    //计算一个数字的每个数之和
    int cal(int n){
        int sum = 0;
        //连除法算出每一位
        while(n != 0){
            sum += (n % 10);
            n /= 10;
        }
        return sum;
    }
    public int movingCount(int threshold, int rows, int cols) {
        //判断特殊情况
        if(threshold <= 0)
            return 1;
        //标记某个格子没有被访问过
        boolean[][] vis = new boolean[rows][cols];
        //记录答案
        int res = 0;
        Queue<ArrayList<Integer> > q = new LinkedList<ArrayList<Integer>>();
        //起点先入队列
        //Arrays.asList()方法是将数组转化成List,是Arrays类中提供的静态方法
        q.offer(new ArrayList<Integer>(Arrays.asList(0, 0)));
        vis[0][0] = true;
        while(!q.isEmpty()){
            //获取符合条件的一步格子
            ArrayList<Integer> node = q.poll();
            res += 1;
            //遍历四个方向
            for(int i = 0; i < 4; i++){
                int x = node.get(0) + dir[i][0];
                int y = node.get(1) + dir[i][1];
                //符合条件的下一步才进入队列
                if(x >= 0 && x < rows && y >= 0 && y < cols && vis[x][y] != true){
                    if(cal(x) + cal(y) <= threshold){
                        q.offer(new ArrayList<Integer>(Arrays.asList(x, y)));
                        vis[x][y] = true;
                    }
                }
            }
        }
        return res;
    }
}

面试题14:剪绳子

public class Solution {
    public int cutRope(int target) {
        int[] arr = new int[target + 1];
        arr[1] = 1;
        for(int i = 2; i <= target; i++){
            for(int j = 1; j < i; j++){
                arr[i] = Math.max(arr[i], 
                Math.max(j, arr[j]) * (Math.max(i - j, arr[i - j])));
            }
        }

        return arr[target];
    }
}
    public int cutRope(int target) {
        if (target == 2 || target == 3)
            return target - 1;
        int res = 1;
        while (target > 4) {
            //如果target大于4,我们不停的让他减去3
            target = target - 3;
            //计算每段的乘积
            res = res * 3;
        }
        return target * res;
    }
    public int cutRope(int target) {
        if (target == 2 || target == 3)
            return target - 1;
        else if (target % 3 == 0) {
            //如果target是3的倍数,绳子全部剪为3
            return (int) Math.pow(3, target / 3);
        } else if (target % 3 == 1) {
            //如果target对3求余等于1,我们剪出一个长度为4的,其他长度都是3
            return 4 * (int) Math.pow(3, (target - 4) / 3);
        } else {
            //如果target对3求余等于2,我们剪出一个长度为2的,其他长度都是3
            return 2 * (int) Math.pow(3, target / 3);
        }
    }

书上的贪婪算法解法:

public class Solution {
    public int cutRope(int target){
    if(target < 2){
        return 0;
    }
    if(target == 2){
        return 1;
    }
    if(target == 3){
        return 2;
    }

    //尽可能多地剪去长度为3的绳子段
    int timesOf3 = target / 3;

    //当绳子最后剩下的长度为4的时候,不能再剪去长度为3的绳子
    //此时更好的方法是把绳子剪成长度为2的炼两段,因为 2*2 >3*1
    if(target - timesOf3 * 3 == 1){
        timesOf3 -= 1;
    }

    int timesOf2 = (target - timesOf3 * 3) / 2;

    return((int)Math.pow(3, timesOf3)) * ((int)Math.pow(2, timesOf2));
    }
}

面试题15:二进制中1的个数

位运算

位运算是指把数字用二进制表示之后,对每一位上0或者1的运算。

以上仅就逻辑变量只有一位的情况得到了逻辑“与”、“或”、“非”、“异或”运算的运算规则。当逻辑变量为多位时,可在两个逻辑变量对应位之间按上述规则进行运算。特别注意,所有的逻辑运算都是按位进行的,位与位之间没有任何联系,即不存在算术运算过程中的进位或借位关系。

public class Solution {
    public int NumberOf1(int n) {
        int count = 0;
        while(n){
            if(n & 1){
                count++;
                n = n >> 1;
            }
        }

        return count;
    }
}

0x80000000存储和表示问题

  1. 负数在内存中的存储形式

  • (1)十进制负数以补码存储于内存上

-8的在内存上存储形式: 1...1000
  • (2)十六进制负数以原码存储在内存上

int i = 0x80000001
// i=-1在内存上表示为 10...01
  • (3)0x80000000的表示值

0x80000000的值为 -2^31

1后面的31位表示序号位,0...0【类似于数组中的0号位】,表示负数中的最小的一位。由于int的最小值为-2^31,排在负数从小到大的第0位,所以int i = 0x80000000 为 -(2^31)+ 0 = -2^31

  • (4)十进制的补码也符合符号位+序号位的原则
    以-1为例,其补码为 1..1
    11...1序号位为第2^31 -1位
    所以其值为 -2^31 + 2^31 -1 = -1 符合预期

  • (5)总结

符号位+序号位原则,序号位从0开始,序号位的值是多少就在最小值的基础上加上多少。好像也是 符合正数的情况~~~。

数值 = 该符号下最小值 + 序号位表示数

在上面的例子中,其中0x表示16进制,f在16进制中就表示十进制数15,这样0xffffff就表示一个16进制的数fffffff

public class Solution {
    public int NumberOf1(int n) {
        int res = 0;
        //遍历32位
        for(int i = 0; i < 32; i++){
            //按位比较
            if((n & (1 << i)) != 0)   
                res++;
        }
        return res;
    }
}
public class Solution {
    public int NumberOf1(int n) {
        int res = 0;
        //当n为0时停止比较
        while(n != 0){  
            //比较一次去掉一个1
            n &= n - 1;
            res++;
        }
        return res;
    }
}
n & (n - 1) == 0;
int a = (0b)m ^ (0b)n
public class Solution {
    public int NumberOf1(int a) {
        int res = 0;
        //当n为0时停止比较
        while(a != 0){  
            //比较一次去掉一个1
            a &= a - 1;
            res++;
        }
        return res;
    }
}

面试题16:数值的整次方

public class Solution {
    public double Power(double base, int exponent) {
        double result = 1.0;

        for(int i = 1; i <= exponent; i++){
            result *=  base; 
        }

        return result;
  }
}
public class Solution {
    public double Power(double base, int exponent) {
        //处理负数次方
        if(exponent < 0){
            base = 1 / base;
            exponent = -exponent;
        }
        double res = 1.0;
        //累乘
        for(int i = 0; i < exponent; i++)
            res *= base;
        return res;
  }
}
public class Solution {
    //快速幂
    private double Pow(double x, int y){ 
        double res = 1;
        while(y != 0){
            //可以再往上乘一个
            if((y & 1) != 0) 
                res *= x;
            //叠加
            x *= x; 
            //减少乘次数
            //使用右移运算符代替了 除以2
            y = y >> 1; 
        }
        return res;
    }
    public double Power(double base, int exponent) {
        //处理负数次方
        if(exponent < 0){
            base = 1 / base;
            exponent = -exponent;
        }
        return Pow(base, exponent);
  }
}

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

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param n int整型 最大位数
     * @return int整型一维数组
     */
    public int[] printNumbers (int n) {
        // write code here
        int maxNum = 0;
        for(int i = 0; i < n; i++){
            maxNum = maxNum + (int)(9 * Math.pow(10,i));
        }
        System.out.println(maxNum);

        int [] arr = new int[maxNum];
        for(int j = 0; j < maxNum; j++){
            arr[j] = j + 1;
        }

        return arr;
    }
}
import java.util.*;
public class Solution {
    public int[] printNumbers (int n) {
        //找到该n+1位数的最小数字
        int end = 1;
        for(int i = 1; i <= n; i++)
            end *= 10;
        //从1遍历到n+1位数的最小数字输出
        int[] res = new int[end - 1];
        for(int i = 1; i < end; i++)
            res[i - 1] = i;
        return res;
    }
}

package algorithm.graph;

import java.util.Arrays;

public class Test {

    public static void main(String[] args) {
        printNumbers(5);
    }

    public static void printNumbers (int n) {
        // write code here
        if (n <= 0){
            return;
        }

        char[] number = new char[(int)Math.pow(10, n) - 1];
        //Java填充字符数组
        Arrays.fill(number, '0');
        number[0] = '0';

        for (int i = 0; i < number.length; i++) {
            System.out.println(i + 1);
        }
    }
}

主要的思想是:把两个数存在String中了,然后将每个数字取出,放到数组,由最末位开始计算,算加法,判断是否进位,进位则前位+1,若超过长度,则copy到新的数组。

或者:两个使用 fiil 填满字符数组,两个字符数组长度之和就是结果

面试题18:删除链表的结点

import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    public ListNode deleteNode (ListNode head, int val) {
        //加入一个头节点
        ListNode res = new ListNode(0);
        res.next = head;
        //前序节点
        ListNode pre = res;
        //当前节点
        ListNode cur = head;
        //遍历链表
        while(cur != null){
            //找到目标节点
            if(cur.val == val){
                //断开连接
                pre.next = cur.next;
                break;
            }
            pre = cur;
            cur = cur.next;
        }
        //返回去掉头节点
        return res.next;
    }
}

    public ListNode deleteNode(ListNode head, ListNode toDeleteNode) {
        
        if(head == null) return null;
        
        //虚构头结点
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        
        //删除的节点不是末尾节点
        if(toDeleteNode.next != null) {
            
            //后一个节点覆盖删除节点
            toDeleteNode.val = toDeleteNode.next.val;
            
            //节点指向后一个节点的下一个节点
            toDeleteNode.next = toDeleteNode.next.next;
            
        }
        //删除的节点是末尾节点
        else {
            ListNode cur = head;
            ListNode pre = dummy;
            
            while(cur != null) {
                
                if(cur == toDeleteNode) {
                    pre.next = cur.next;
                }
                
                pre = cur;
                cur = cur.next;
            }
        }
        return dummy.next ;
    }

第一种解法

此类题目,肯定是可以采用递归来解决的,递归循环找到每个不重复的节点,重新组成一个有序链表即可,代码如下

public ListNode firstdeleteDuplication(ListNode<Integer> pHead) {
        if(null == pHead || null == pHead.next){
            return pHead;
        }
        if(pHead.val == pHead.next.val){
            ListNode node = pHead.next;
            //找到下一个phead不相同的第一个节点
            while (node != null && node.val == pHead.val ){
                node = node.next;
            }
            return firstdeleteDuplication(node);
        }else {
            pHead.next =firstdeleteDuplication(pHead.next);
            return pHead;
        }
    }

第二个解法

在第一种解法中,我们采用了递归的方式,我们也可以采用非递归的方式,直接循环判断,代码如下

public ListNode secondDeleteDuplication(ListNode<Integer> pHead) {
        if(null == pHead || null == pHead.next){
            return pHead;
        }
        //定义一个虚拟头节点
        if(pHead == null || pHead.next == null) return pHead;
        ListNode temp = new ListNode(-1);
        //虚拟头结点的下一个结点设为头结点
        temp.next = pHead;
        ListNode pre = temp;
        while(pHead != null && pHead.next != null){
            ListNode next = pHead.next;
            if(pHead.val == next.val){
                //循环找到重复数字的最后一个结点
                while(next != null && pHead.val == next.val){
                    next = next.next;
                }
                pre.next = next;
                pHead = next;
            }else{
                pre = pHead;
                pHead = pHead.next;
            }
        }
        return temp.next;
    }

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

import java.util.*;
public class Solution {
    public boolean match (String ss, String pp) {
        // 技巧:往原字符头部插入空格,这样得到 char 数组是从 1 开始,而且可以使得 f[0][0] = true,可以将 true 这个结果滚动下去
        int n = ss.length(), m = pp.length();
        ss = " " + ss;
        pp = " " + pp;
        //两者都转化成字符串数组
        char[] s = ss.toCharArray();
        char[] p = pp.toCharArray();
        
        boolean[][] f = new boolean[n + 1][m + 1];
        // 技巧:往原字符头部插入空格,这样得到 char 数组是从 1 开始,而且可以使得 f[0][0] = true,可以将 true 这个结果滚动下去
        f[0][0] = true;
        // f(i,j) 代表考虑 s 中的 1~i 字符和 p 中的 1~j 字符 是否匹配
        for (int i = 0; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                // 如果下一个字符是 '*',则代表当前字符不能被单独使用,跳过
                if (j + 1 <= m && p[j + 1] == '*') continue;

                // 对应了 p[j] 为普通字符和 '.' 的两种情况
                if (i - 1 >= 0 && p[j] != '*') {
                    f[i][j] = f[i - 1][j - 1] && (s[i] == p[j] || p[j] == '.');
                }

                // 对应了 p[j] 为 '*' 的情况
                else if (p[j] == '*') {
                    f[i][j] = (j - 2 >= 0 && f[i][j - 2]) || (i - 1 >= 0 && f[i - 1][j] && (s[i] == p[j - 1] || p[j - 1] == '.'));
                }
            }
        }
        return f[n][m];
    }
}

i从0开始循环考虑的是上面这种情况

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

import java.util.*;
public class Solution {
    //遍历字符串的下标
    private int index = 0;
    //有符号判断
    private boolean integer(String s){
        if(index < s.length() && (s.charAt(index) == '-' || s.charAt(index) == '+'))
            index++;
        return unsigned_integer(s);
    }
    //无符号数判断
    private boolean unsigned_integer(String s){
        int temp = index;
        while(index < s.length() && (s.charAt(index) >= '0' && s.charAt(index) <= '9'))
            index++;
        return index > temp;
    }
    public boolean isNumeric (String str) {
        //先判断空串
        if(str == null || str.length() == 0)
            return false;
        //去除前面的空格
        while(index < str.length() && str.charAt(index) == ' ')
            index++;
        int n = str.length() - 1;
        //去除字符串后面的空格
        while(n >= 0 && str.charAt(n) == ' ')
            n--;
        //限制的长度比下标少1
        n++;
        //全是空格情况
        if(n < index)
            return false;
        //判断前面的字符是否是有符号的整数
        boolean flag = integer(str);
        //如果有小数点
        if(index < n && str.charAt(index) == '.'){
            index++;
            //小数点前后有无数字可选
            flag = unsigned_integer(str) || flag; 
        }
        //如果有e
        if(index < n && (str.charAt(index) == 'e' || str.charAt(index) == 'E')){
            index++;
            //e后面必须全是整数
            flag = flag && integer(str);
        }
        //是否字符串遍历结束
        return flag && (index == n);
    }
}
import java.util.regex.Pattern;
public class Solution {

    public boolean isNumeric (String str) {
       //正则表达式匹配
        String pattern = "(\\s)*[+-]?((\\d+(\\.(\\d+)?)?)|(\\.\\d+))([Ee][+-]?\\d+)?(\\s)*";
        //根据匹配值返回
        return Pattern.matches(pattern, str);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值