zoukankan      html  css  js  c++  java
  • 剑指Offer系列之题51~题55

    51.数组中重复的数字

    在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

    暴力解:辅助map存储元素,当重复时直接返回;

    排序后根据数组特点交换数字;


    1.暴力解:

    import java.util.Map;
    import java.util.HashMap;
    public class Solution {
        // Parameters:
        //    numbers:     an array of integers
        //    length:      the length of array numbers
        //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
        //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
        //    这里要特别注意~返回任意重复的一个,赋值duplication[0]
        // Return value:       true if the input is valid, and there are some duplications in the array number
        //                     otherwise false
        public boolean duplicate(int numbers[],int length,int [] duplication) {
            if(length<=1)
                return false;
            //数字在0~length-1的范围内
            Map<Integer,Integer> map=new HashMap<>();
            for(int i=0;i<length;++i){
                if(numbers[i]<0 || numbers[i]>length-1)//输入无效
                    return false;
                if(map.containsKey(numbers[i])){
                    duplication[0]=numbers[i];
                    return true;
                }
                map.put(numbers[i],1);
            }
            return false;
        }
    }
    

    2.根据数组特点:

    import java.util.Map;
    import java.util.HashMap;
    public class Solution {
        // Parameters:
        //    numbers:     an array of integers
        //    length:      the length of array numbers
        //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
        //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
        //    这里要特别注意~返回任意重复的一个,赋值duplication[0]
        // Return value:       true if the input is valid, and there are some duplications in the array number
        //                     otherwise false
        public boolean duplicate(int numbers[],int length,int [] duplication) {
            if(length<=1)
                return false;
            //数字在0~length-1的范围内  若无重复,则排序后数组正好为 0~length-1
    
            for(int i=0;i<length;++i){
                while(numbers[i]!=i){//当不等于下标时,说明无序,则将该数与对应下标位置交换
                    int temp=numbers[i];
                    if(temp==numbers[temp]){//若当前数和该数为下标的位置的数相等,说明重复
                        duplication[0]=temp;
                        return true;
                    }
                    numbers[i]=numbers[temp];//交换
                    numbers[temp]=temp;
                }
            }
    
            return false;
        }
    }
    

    52.构建乘积数组

    给定一个数组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]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * ... * A[n-1],B[n-1] = A[0] * A[1] * ... * A[n-2];)

    暴力解:依次遍历,复杂度过高;

    将B看作矩阵,分别求上三角和下三角,然后相乘


    1.矩阵:

    public class Solution {
        public int[] multiply(int[] A) {
            //不能用除法 定义两数组,一个计算前半部分 一个计算后半部分
            int len=A.length;
            int B[]=new int[len];
    
            if(len!=0){
                B[0]=1;
                //下三角
                for(int i=1;i<len;++i){
                    B[i]=B[i-1]*A[i-1];
                }
                int temp=1;
                //上三角
                for(int j=len-2;j>=0;--j){
                    temp*=A[j+1];//上三角
                    B[j]*=temp;//乘积
                }
            }
            return B;
        }
    }
    

    53.正则表达式匹配

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

    分情况判断,注意边界问题(代码完整性)


    1.递归:

    public class Solution {
        public boolean match(char[] str, char[] pattern)
        {
            if(str==null || pattern==null)
                return false;
            return matchCore(str,pattern,0,0);
        }
    
        public boolean matchCore(char []str,char []pattern,int strIndex,int patternIndex ){
            //当两者都走完 或 两者都为""
            if(strIndex==str.length && patternIndex ==pattern.length)
                return true;
            //当pat先走完
            if(strIndex!=str.length && patternIndex ==pattern.length)
                return false;
            //若模式串第2个是*,且字符串第1个跟模式串第1个匹配,分3种匹配模式;如不匹配,模式串后移2位
            if(patternIndex +1<pattern.length && pattern[patternIndex +1]=='*'){//当pat下一位是 *时
                if((strIndex!=str.length && str[strIndex]==pattern[patternIndex]) || (pattern[patternIndex]=='.' && strIndex!=str.length)){
                    //1:str指针右移,pat不变  令pat此处为与str相等的多个字符
                    //2:str右移,pat右移两位  令pat此处为与str相等的一个字符
                    //3:str不变,pat右移两位  令pat此处为空
    
                    //此处传参不可用++x,x++,只可用x+1
                    return matchCore(str,pattern,strIndex,patternIndex +2)|| matchCore(str,pattern,strIndex+1,patternIndex +2) ||matchCore(str,pattern,strIndex+1,patternIndex );
                }else{//字符串第一个和模式串第一个不匹配,模式串后移2位
                    return matchCore(str,pattern,strIndex,patternIndex +2);
                }
            }
    
            //如果模式串的下一位不是*,则判断字符串与模式串当前位是否匹配,或者模式串当前位是否为 .
            if(( strIndex != str.length && str[strIndex] == pattern[patternIndex] )  || (pattern[patternIndex] == '.' &&  strIndex != str.length))
                return matchCore(str,pattern,++strIndex,++patternIndex );
            return false;
        }
    }
    

    54.表示数值的字符串

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

    需要判断多种情况,保证考虑周全(代码完整性)


    1.枚举:

    public class Solution {
        public boolean isNumeric(char[] str) {
            if(str==null || str.length<=0)
                return false;
            int count=0;//+ -的数量
            int pCount=0;//. 的数量
            for(int i=0;i<str.length;++i){
                char c=str[i];
                if(c<48 || c>57){
                    //当不是数字
                    if(c=='+' || c=='-'){//正负号在第一位或是幂
                        count++;
                        //若+ -号后不是数字,则false
                        if(i!=0 && (i<str.length-1 && (str[i+1] <48 || str[i+1]>57 )))
                            return false;
                        //若+ -号前不是e,则false
                        if(i!=0 && (i>0 && (str[i-1]!='e' && str[i-1]!='E')))
                            return false;
                        //若正负号在开头,则继续
                    }else if(c=='e' || c== 'E'){
                        if(i==str.length-1)
                            return false;
                        //判断e后是否为数字 或 正负号跟数字,不是则false
                        if(i<str.length-1 && (str[i+1]<48 || str[i+1]>57)){
                            if(str[i+1]!='-' && str[i+1]!='+')
                                return false;
                        }
                    }else if(c=='.'){
                        //判断是否为 . ,若在 . 前出现不是首位的正负号则返回false:-10e-2.3 返回false
                        if(pCount>0)//若已出现过 . ,则返回false
                            return false;
                        //若首位是正负号,将正负号数量-1,若count此时大于0说明在 . 前有两个正负号,返回false
                        if(str[0]=='+' || str[0]=='-'){
                            count--;
                            if(count>0)
                                return false;
                        }else if(count>0){
                            return false;
                        }
                        pCount++;
                    }else{
                        return false;
                    }
                }
            }
            return true;
        }
    }
    

    2.正则表达式:

    [\+\-]?:正或负符号出现与否

    \d*:整数部分是否出现,如-.34 或 +3.34均符合

    (\.\d+)?:如果出现小数点,那么小数点后面必须有数字;否则一起不出现

    ([eE][\+\-]?\d+)?:如果存在指数部分,那么e或E肯定出现,+或-可以不出现,紧接着必须跟着整数;或者整个部分都不出现

    public class Solution {
        public boolean isNumeric(char[] str) {
            String string = String.valueOf(str);
            return string.matches("[\+\-]?\d*(\.\d+)?([eE][\+\-]?\d+)?");
        }
    }
    

    55.字符流中第一个不重复的字符

    请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。

    输出描述:如果当前字符流没有存在出现一次的字符,返回#字符。

    考虑辅助map和列表存储映射以及出现一次的元素;或者使用LinkedHashMap。


    1.hashmap:

    import java.util.Map;
    import java.util.HashMap;
    import java.util.List;
    import java.util.ArrayList;
    public class Solution {
        Map<Character,Integer> map=new HashMap<>();
        List<Character> res=new ArrayList<>();
        //Insert one char from stringstream
        public void Insert(char ch)
        {
            if(!map.containsKey(ch)){
                map.put(ch,1);
                res.add(ch);//将第一次出现的元素加入列表
            }else{
                //如果列表包含该重复元素,则将其移除
                if(res.contains(ch))
                    res.remove(Character.valueOf(ch));
            }
        }
      //return the first appearence once char in current stringstream
        public char FirstAppearingOnce()
        {
            if(!res.isEmpty())
                return res.get(0);
            return '#';
        }
    }
    

    如有错误,欢迎指正

  • 相关阅读:
    PHP观察者模式 (转)
    PHP单例模式 (转)
    PHP解决并发问题的几种实现(转)
    php结合redis实现高并发下的抢购、秒杀功能 (转)
    使用 redis 减少 秒杀库存 超卖思路 (转)
    mysql视图学习总结(转)
    mysql 存储过程
    PHP中的魔术方法和关键字
    bzoj3462DZY Loves Math II
    bzoj1453[Wc]Dface双面棋盘
  • 原文地址:https://www.cnblogs.com/lfz1211/p/12711654.html
Copyright © 2011-2022 走看看