剑指Offer/51-55

51、构建乘积数组

题目描述

给定一个数组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];) 对于A长度为1的情况,B无意义,故而无法构建,因此该情况不会存在。

在这里插入图片描述可知:

left[i+1] = A[0]*...A[i-1]*A[i]
right[i+1] = A{i+2]*...*A[n-1]

于是,

left[i+1] = left[i] * A[i]
right[i] = right[i+1] * A[i+1]

所以,我们可以先把所有的left[i]求出,right[i]求出。

class Solution {
    public int[] constructArr(int[] a) {
        if(a==null||a.length==0) return new int[0];
        int[] b = new int[a.length];
        b[0] = 1; 
        for(int i=1;i<a.length;i++){
            b[i] = b[i-1]*a[i-1];
        }
        //b[i] = b[i+1]*a[i+1]这个不能直接使用,因为现在b里面已经有值了,不但单纯是b[i+1]了
        //计算的应该是b[i]*[a[i+1]*a[i+2]*...a[n]]
        int temp = 1;
        for(int i=a.length-2;i>=0;i--){
            temp*=a[i+1];
            b[i] = b[i]*temp;
        }
        return b;
    }
}

52、正则表达式

题目描述

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

class Solution {
    public boolean isMatch(String s, String p) {
        if(s==null&&p==null) return true;
        return matchString(s.toCharArray(),0,p.toCharArray(),0);
    }
    private boolean matchString(char[] str,int i, char[] pattern,int j){
        if(i == str.length&& j == pattern.length) return true;
        if(i<str.length&&j==pattern.length) return false;
        /**
            如果p的下一个位置是*
            如果模式匹配字符的下一个字符是‘*’,且pttern当前字符和str的当前字符匹配,:有以下三种可能情况
           (1)pttern当前字符能匹配 str 中的 0 个字符:match(str, pattern+2)(跳到*的下一个,指*前面的字符出现了0次,则str不动,只移动pattern)
           (2)pttern当前字符能匹配 str 中的 1 个字符:match(str+1, pattern+2)(指*前面的字符出现了1次)
           (3)pttern当前字符能匹配 str 中的 多 个字符:match(str+1, pattern)(pattern不动,可以当做是当做重复前一个字符)
         */
        if(j+1<pattern.length&&pattern[j+1]=='*'){
            //当前点匹配
            if((i<str.length&&pattern[j]=='.')||i<str.length&&str[i]==pattern[j]){
                return matchString(str,i,pattern,j+2)||matchString(str,i+1,pattern,j+2)||matchString(str,i+1,pattern,j);
            }else{
                //当前字符不匹配,则当做*前的出现了0次,pattern后移,继续匹配 
                //如 bbc  a*b*c--> 下一个是*,b a不匹配,则继续比较 bbc b*c
                return matchString(str,i,pattern,j+2);
            }
        }
        //pattern下一个不是*,且和str匹配,就依次向后匹配
        if(i<str.length&&(str[i]==pattern[j]||pattern[j]=='.')){
            return matchString(str,i+1,pattern,j+1);
        }
        return false;
    }
}

53、表示数值的字符串

题目描述

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

public boolean isNumber(String s) {
    // s为空对象或 s长度为0(空字符串)时, 不能表示数值
    if(s == null || s.length() == 0) return false;
    // 标记是否遇到数位、小数点、‘e’或'E'
    boolean isNum = false, isPoint = false, ise_or_E = false;
    // 删除字符串头尾的空格,转为字符数组,方便遍历判断每个字符
    char[] str = s.trim().toCharArray();
    for(int i=0; i<str.length; i++) {
        // 判断当前字符是否为 0~9 的数位
        if(str[i] >= '0' && str[i] <= '9') isNum = true;
            // 遇到小数点
        else if(str[i] == '.') {
            // 小数点之前可以没有整数,但是不能重复出现小数点、或出现‘e’、'E'
            if(isPoint || ise_or_E) return false;
            isPoint = true; // 标记已经遇到小数点
        }
        // 遇到‘e’或'E'
        else if(str[i] == 'e' || str[i] == 'E') {
            // ‘e’或'E'前面必须有整数,且前面不能重复出现‘e’或'E'
            if(!isNum || ise_or_E) return false;
            // 标记已经遇到‘e’或'E'
            ise_or_E = true;
            // 重置isNum,因为‘e’或'E'之后也必须接上整数,防止出现 123e或者123e+的非法情况
            isNum = false;
        }
        else if(str[i] == '-' ||str[i] == '+') {
            // 正负号只可能出现在第一个位置,或者出现在‘e’或'E'的后面一个位置
            if(i!=0 && str[i-1] != 'e' && str[i-1] != 'E') return false;
        }
        // 其它情况均为不合法字符
        else{
            return false;
        }
    }
    return isNum;
}

直接用正则:

import java.util.regex.Pattern;
 
public class Solution {
    public static boolean isNumeric(char[] str) {
        String pattern = "^[-+]?\\d*(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?$";
        String s = new String(str);
        return Pattern.matches(pattern,s);
    }
}

54、字符流中第一个不重复的字符

题目描述

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

用Hashmap记录次数,然后用一个变长字符串(StringBuilder)记录插入的元素

package M51TO55;

import java.util.HashMap;

public class SoluInsert {
    //Insert one char from stringstream
    HashMap<Character,Integer> map = new HashMap<>();
    StringBuilder str = new StringBuilder();
    public void Insert(char ch) {
        str.append(ch);
        if (map.containsKey(ch)){
            map.put(ch,map.get(ch)+1);
        }else{
            map.put(ch,1);
        }
    }
    //return the first appearence once char in current stringstream
    public char FirstAppearingOnce(){
        for (int i=0;i< str.length();i++){
            if (map.get(str.charAt(i))==1){
                return str.charAt(i);
            }
        }
        return '#';
    }
}

55、链表中环的入口结点

题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

使用HashSet,依次添加节点,如果节点中出现重复的点,则存在环:
注意:HashSet不能添加重复的元素,当调用add(o)方法时候,会判断o是否已经存在,如果o已经存在则返回false,不存在则插入返回true
在这里插入图片描述

public class EntryNodeOfLoop {
    public ListNode EntryNodeOfLoop(ListNode pHead) {
        // 想法1:
        //a+(n+1)b+nc=2(a+b)⟹a=c+(n−1)(b+c)(在慢指针走完一圈前快指针就会追上他,极限情况是循环链表,刚好走完一圈相遇)
        //有了 a=c+(n−1)(b+c) 的等量关系,而b+c是环长。我们会发现:
        // 从相遇点到入环点的距离再加上n−1 圈的环长,恰好等于从链表头部到入环点的距离。
        //当发现 slow 与 fast 相遇时,我们再额外使用一个指针 ptr。
        // 0起始,它指向链表头部;随后,它和 slow 每次向后移动一个位置。最终,它们会在入环点相遇。
        //想法二:用容器储存每一个节点,当遍历到第一个重复的节点时,这个节点就是重复的、

        //这里实现想法一:
        if(pHead == null || pHead.next == null){
            return null;
        }
        ListNode fast = pHead;
        ListNode slow = pHead;
        while(fast!=null&&fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast==slow) break;
        }
        slow = pHead;
        while(fast!=slow){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

二:

package M51TO55;
import M10TO15.ListNode;
import java.util.HashSet;

public class SoluEntryNodeOfLoop {
    public ListNode EntryNodeOfLoop(ListNode pHead){
        HashSet<ListNode> set = new HashSet<>();
        while (pHead!=null){
            if (set.add(pHead)==false){
                return pHead;
            }else {
                pHead=pHead.next;
            }
        }
        return null;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值