剑指offer——其二

正则匹配

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

采用递归的方式:

str的指针i和pattern的指针j:
有些比如str="",pattern=".*"|| str="",pattern=""等情况也需要考虑

如果同时扫描完 str和pattern,返回 true

如果扫描完pattern却没有扫描完str,返回false

如果j有下一个字符且下一个是*
	如果str没有扫描完且pattern[j]==str[i]||pattern[j]=='.'
		return match(str,pattern,i,j+2);匹配0次
			   match(str,pattern,i+1,j+2);匹配1次
			   match(str,pattern,i+1,j);匹配多次
	否则 match(str,pattern,i,j+2);匹配不上返回0次

如果str没有扫描完且pattern[j]=='.'||str[i]==pattern[j]
	return match(str,pattern,i+1,j+1);
return false;

public boolean match(char[] str,char[] pattern,int i,int j){
		if(str.length==i&&pattern.length==j) return true;
 	if(str.length!=i&&pattern.length==j) return false;
	if(j<pattern.length-1&&pattern[j+1]=='*'){ 	
		if(i!=str.length&&(str[i]==pattern[j]||pattern[j]=='.'))
			return match(str,pattern,i+1,j)||match(str,pattern,i,j+2)||match(str,pattern,i+1,j+2);
		else {
			return match(str, pattern, i, j+2);}
    }
	if(str.length!=i&&(pattern[j]=='.'||str[i]==pattern[j])) return match(str, pattern, i+1, j+1);
    return false;
}

判断字符串是否为数值

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

正则表达式,简单明了:

import java.util.regex.Pattern;
public class Solution {
    public boolean isNumeric(char[] str) {

        String pattern = "^[-,+]?\\d*(?:\\.\\d*)?(?:[e,E][+,-]?\\d+)?$";
        String s = new String(str);
        return Pattern.matches(pattern,s);
    }
}

"[1]?\d(?:\.\d)?(?:[e,E][+,-]?\d+)?$";

^$正则表达的起始和截止

[-,+]?:+或-出现0次或1次

\d*数字出现多次

(?:.\d*)?:(小数点+数字可出现多次)这些东西出现0次或1次
另一个()同理

找出字符流中第一个只出现一次的字符.

当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。如果当前字符流没有存在出现一次的字符,返回#字符

采用字符哈希的方法,记录读入的字符,并设置一个队列,如果出现就入队.

获取时,判断队首元素的哈希数组是否为1.

import java.util.Queue;
import java.util.LinkedList;
import java.lang.Character;
public class Solution {
  int[] charCnt=new int[128];
  Queue<Character> queue=new LinkedList<Character>();
    //Insert one char from stringstream
    public void Insert(char ch)
    {
          charCnt[ch]++;
          queue.add(ch);
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
      Character CHAR=null;
      char c=0;
      while((CHAR=queue.peek())!=null){
        c=CHAR.charValue();
        if(charCnt[c]==1)
          return c;
        else queue.remove();
      }
      return '#';
    }
}

判断一个链表是否有环

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

思路:快慢指针,当两者相遇,从相遇点和起点一起走再次相遇就是环的起点。

/*
 public class ListNode {
    int val;
    ListNode next = null;

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

    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        ListNode low=pHead,fast=pHead;
        ListNode meet=null;
        while(fast!=null){
          low=low.next;
          fast=fast.next;
          if(fast!=null)
            fast=fast.next;
          if(fast==low)
          {meet=fast;
            break;}
        }
      if(meet==null) return null;
      while(pHead!=null&&meet!=null){
        if(pHead==meet)
          return pHead;
        pHead=pHead.next;
        meet=meet.next;
      }
      return null;
    }
}

删除链表中的重复节点

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
      if(pHead==null||pHead.next==null) return pHead;
      ListNode head=new ListNode(0);
      head.next=pHead;
      ListNode p=head.next,q=head;
      while(p!=null){
        if(p.next!=null&&p.val==p.next.val){
          while(p.next!=null&&p.val==p.next.val)
            p=p.next;
        q.next=p.next;
        p=p.next;
        }else{
          q=q.next;
          p=p.next;
        }
      }
      return head.next;
    }
}

这个代码比较好是因为它创建了头部节点。设两个指针p和q,以p为探索指针,向前寻找重复的最后一个节点,将q的下一个设为p的下一个节点,然后继续寻找,更新q的下一个节点,直到找到下一个没有重复的节点时再更新q的节点。

二叉树中序遍历问题

给定一个二叉树和其中一个节点,请找出中序遍历顺序的下一个节点并返回

思路:这里有几种情况,

如果该节点有右子树,那就是右子树或者右子树的最左节点

如果该节点没有右子树,该节点是其父节点的左子树,那么就是父节点

如果该节点没有右子树,该节点是其父节点的右子树,那么就是一直寻找到不是父节点右子树的那个父亲..

还要考虑特殊情况,比如本树最后一个节点结果为null.

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;//左子树
    TreeLinkNode right = null;//右子树
    TreeLinkNode next = null;//父节点
 
    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
         if(pNode==null) return null;
         if(pNode.right!=null){//情况1
          pNode=pNode.right;
          while(pNode.left!=null)//寻找右子树的最左节点
            pNode=pNode.left;
          return pNode;}
        if(pNode.right==null){
          if(pNode.next!=null&&pNode==pNode.next.left) return pNode.next;//情况2
          if(pNode.next==null) return null;//防止根节点的特殊情况
          if(pNode==pNode.next.right){//情况3
            while(pNode.next!=null&&pNode==pNode.next.right){
              pNode=pNode.next;
            }
            if(pNode.next==null) return null;//特殊情况本树最后一个节点
            return pNode.next;
          }
        }
      return null;
    }
}

  1. -,+ ↩︎

posted @ 2020-06-10 15:18  梅落南山  阅读(124)  评论(0编辑  收藏  举报