牛客网剑指Offer67题及题解(Java实现)

 ̄綄美尐妖づ 提交于 2020-01-11 23:50:37

数组

1 二维数组中的查找

题目描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

思路
由于数组从左至右,从上至下都是有序的,可以先判断每行最右边的数字即每行最大的数字是否小于目标值,如果小于的话则跳到下一行,如果在下一行没有找到则继续跳到下一行,依次类推。
其中在每一行使用二分查找查找目标值。

public class Solution {
    public boolean Find(int target, int [][] array) {
    	//如果数组为空返回false
        if(array.length==0||array[0].length==0)
            return false;
        int row=0;//从第一行开始
        while(row<array.length){//循环到最后一行
            if(array[row][array[0].length-1]<target){//如果该行最后一列小于目标值
                row++;//跳到下一行
            }
            else {//在行中使用二分查找
                int low=0;
                int high=array[0].length-1;
                while(low<=high){
                    int mid=low+(high-low)/2;
                    if(array[row][mid]<target)
                        low=mid+1;
                    else if(array[row][mid]>target)
                        high=mid-1;
                    else
                        return true;
                }//如果没找到 跳到下一行 不然会无限循环
                row++;
            }
        }
        return false;
    }
}

2 数组中重复的数字

题目描述
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。
思路
使用哈希表,判断当前遍历的元素是否已存在,若存在返回true。

public class Solution {
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(numbers!=null){
            HashMap<Integer,Integer> map=new HashMap<>();
            for(int num:numbers){
                if(map.containsKey(num)){
                    duplication[0]=num;
                    return true;
                }else
                    map.put(num,1);
            }
        
        duplication[0]=-1;
        return false;
    }
}

3 构建乘积数组

题目描述
给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。
思路
按照题目描述构建算法即可。

public class Solution {
    public int[] multiply(int[] A) {
        int[] B=new int[A.length];//长度和A一样
        for(int i=0;i<A.length;i++){//依次计算乘积并赋值
            int mul=1;
            for(int j=0;j<i;j++)//计算0-i-1的乘积
                mul*=A[j];
            for(int j=i+1;j<A.length;j++)//计算i+1到n-1的乘积
                mul*=A[j];
            B[i]=mul;//赋值
        }
        return B;
    }
}

字符串

1 替换空格

题目描述
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思路
构建一个stringbuffer,如果遇到空格则附加%20,否则附加原字符。

public class Solution {
    public String replaceSpace(StringBuffer str) {
        StringBuffer sb=new StringBuffer();
    	for(int i=0;i<str.length();i++){
            if(str.charAt(i)!=' ')
                sb.append(str.charAt(i));
            else
                sb.append("%20");
        }
        return sb.toString();
    }
}

2 正则表达式匹配

题目描述
请实现一个函数用来匹配包括.*的正则表达式。模式中的字符’.‘表示任意一个字符,而’*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串aaa与模式a.aab*ac*a匹配,但是与aa.aab*a均不匹配
思路
利用递归判断,定义两个指针分别遍历字符串和匹配字符串,若可以同时到达末尾说明可以完全匹配,否则说明不能完全匹配。

public class Solution {
    public boolean match(char[] str, char[] pattern){
        //任意一个为空,则匹配失败
        if(str==null||pattern==null)
            return false;
        return match(str,0,pattern,0);
    }
    public boolean match(char[] str, int s,char[] pattern,int p){
        //如果字符串和匹配字符串都到达了末尾,则说明匹配成功
        if(s==str.length&&p==pattern.length)
            return true;
        //如果字符串未遍历结束,但匹配字符串已结束,匹配失败
        if(s<str.length&&p==pattern.length)
            return false;
        //如果匹配字符串的下一个字符是*
        if(p<pattern.length-1&&pattern[p+1]=='*'){
            //如果当前字符串字符和匹配字符串字符相同或者匹配字符为.
            if(s<str.length&&(str[s]==pattern[p]||pattern[p]=='.'))
                return match(str, s+1, pattern, p)//.*可以匹配多个字符 如aa匹配a*
                        ||match(str, s, pattern, p+2);//忽略当前匹配字符串的2个字符 如a不匹配b*,可跳过
            else
                return match(str, s, pattern, p+2);//匹配失败
        }
        if(s<str.length&&(str[s]==pattern[p]||pattern[p]=='.')){
            return match(str,s+1,pattern,p+1);
        }
        return false;
    }
}

3 字符流中第一个不重复的字符

题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述
如果当前字符流没有存在出现一次的字符,返回#字符。
思路
定义一个ArrayList集合存储输入流的字符,一个哈希表记录各字符的出现次数,遍历当前集合返回第一个出现次数为1的字符,如果没有就返回#

import java.util.*;
public class Solution {
    //Insert one char from stringstream
    HashMap<Character,Integer> map=new HashMap<>();
    ArrayList<Character> list=new ArrayList<>();
    
    public void Insert(char ch){
        if(map.containsKey(ch))//如果存在就加一
            map.put(ch,map.get(ch)+1);
        else//不存在就放入map,并赋初值1
            map.put(ch,1);
        list.add(ch);//保存到集合中
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce(){
        //遍历集合返回在哈希表中出现次数为1的字符
        for(char c:list){
            if(map.get(c)==1)
                return c;
        }
        return '#';//如果没有则返回#
    }
}

4 表示数值的字符串

题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。
思路
^表示以…开头
[+-]表示有0或1个正负号
[0-9]*表示任意个数字
(\\.[0-9]*)?表示0或1个 (小数点+任意个数字) 如.1.123
([eE][+-]?[0-9]+)? 表示0或1个( e/E 0或1个正负号 一或多个数字) 如e+1e-12e2
$表示以…结尾

public class Solution {
    public boolean isNumeric(char[] str) {
        String s="^[+-]?[0-9]*(\\.[0-9]*)?([eE][+-]?[0-9]+)?$";
        String line=new String(str);
        return line.matches(s);
    }
}

待更新

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!