剑指offer51-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];)

import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        int[] B=new int[A.length];
        for(int i=0;i<A.length;i++){
            B[i]=1;
            for(int j=0;j<A.length;j++){
                if(j!=i){
                    B[i]*=A[j];
                }
            }
        }
        return B;
    }
}

52 表示数值的字符串

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

 

[-+]?

正负号后面的 ? 后缀表示这个负号是可选的,表示有0到1个负号或者正号

\\d*

\d的含义和[0-9]一样。它匹配一个数字。后缀 * 指引它可匹配零个或者多个数字。

(?:\\.\\d*)?

(?: …)?表示一个可选的非捕获型分组。* 指引这个分组会匹配后面跟随的0个或者多个数字的小数点。

(?:[eE][+\\-]?\d+)?

这是另外一个可选的非捕获型分组。它会匹配一个e(或E)、一个可选的正负号以及一个或多个数字。

import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Solution {
    public boolean isNumeric(char[] str) {
         String s = new String(str);
        s = s.trim();
        String regex = "^[-+]?[0-9]+[.]?\\d*[eE][-+]?\\d+$|^[-+]?[0-9]+[.]?\\d*$|^[-+]?[.][0-9]+[eE]?[-+]?\\d+$|^[-+]?[.][0-9]+$";
                //"^[-+]?\\d*(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?$"

        Pattern pattern = Pattern.compile(regex);
        Matcher m = pattern.matcher(s);
        return m.matches();
    }
}

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

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

import java.util.Map;
import java.util.LinkedHashMap;
public class Solution {
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        stringBuilder.append(ch);
    }
    StringBuilder stringBuilder = new StringBuilder();
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        String str = stringBuilder.toString();
        Map<Character,Integer> map = new LinkedHashMap<>();
        for(int i = 0; i < str.length(); i++){
            int count = map.getOrDefault(str.charAt(i),0)+1;
            map.put(str.charAt(i),count);
        }
        for(Map.Entry<Character, Integer> entry: map.entrySet()) {
            if(entry.getValue() == 1){
                return entry.getKey();
            }
        }
        return '#';
    }
}

54链表中环的入口节点

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

 

请问如何判断一个单向链表存在回路?

 

参考回答:

 

方法1:用一个指针数组A,存储已访问过的节点。用一个指针p,每次在链表上移动一步,然后与指针数组A比较,若数组中没有指针与p相同,说明第一次访问p,将p放入数组中;若有指针与p相同,则存在环路,且第一次相同的节点就是环的入口点。

 

链表长度为n,则需要空间o(n),且每次要与指针数组比较,时间复杂度为 O(n^2)。

 

方法2:在节点上记录该节点是否被访问过,如果在指针移动过程中遇到已访问过的节点,说明存在环路。同样地,第一次相同的节点就是环的入口点。

 

方法3:用两个指针,pSlow,pFast,一个慢一个快,慢的一次跳一步,,快的一次跳两步,如果快的能追上慢的就表示有环(pSlow == pFast )。

 

 

public class Solution {
    public ListNode EntryNodeOfLoop(ListNode h){
            if(h == null || h.next == null)
                return null;
            ListNode slow = h;
            ListNode fast = h;
            while(fast != null && fast.next != null ){
                slow = slow.next;
                fast = fast.next.next;
                if(slow == fast){
                    ListNode p=h;

                    ListNode q=slow;//相当于让q指向了m1
    
                    while(p != q){
                        p = p.next;
                        q = q.next;
                    }
                    if(p == q)
                        return q;
                }
            }
            return null;
    }

 

 

 

import java.util.Map;
import java.util.HashMap;
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        Map<ListNode,Integer> map = new HashMap<>();
        while(!map.containsKey(pHead)){
            if(pHead.next == null){
                return null;
            }
            map.put(pHead,1);
            pHead = pHead.next;
        }
              return pHead;
    }
}

55删除链表中重复的节点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

时间复杂度:O(n)
空间复杂度:O(1)

借助辅助头结点,可避免单独讨论头结点的情况。设置两个结点 pre 和 cur,当 cur 和 cur.next 值相等,cur 一直向前走,直到不等退出循环,这时候 cur 指的值还是重复值,调整 cur 和 pre 的指针再次判断

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

    ListNode(int val) {
        this.val = val;
    }
}
*/
时间复杂度:O(n)
空间复杂度:O(1)
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
        ListNode head = new ListNode(-1);
        head.next = pHead;
        ListNode cur =pHead;
        ListNode pre = head;
        while(cur != null){
            if(cur.next != null && cur.val == cur.next.val){
        //
pre=cur;如果要保留重复的数字,如输入1-1-2,输出1-2,则只需要在此处加入pre=cur;即可
        while(cur.next != null && cur.val == cur.next.val){ cur = cur.next; } cur = cur.next; pre.next = cur; }else{ pre = cur; cur = cur.next; } } return head.next; } }

 

//pre=cur;如果要保留重复的数字,如输入1-1-2,输出1-2,则只需要在此处加入pre=cur;即可
[//Pre=cur; rúguǒ yào bǎoliú chóngfù de shùzì, rú shūrù 1-1-2, shūchū 1-2, zé zhǐ xūyào zài cǐ chù jiārù pre=cur; jí kě]
// pre = cur; To keep duplicate numbers, such as 1-1-2 inputs, outputs 1-2, only need to add pre = cur here; can
posted @ 2020-06-05 13:41  我们村里的小花儿  阅读(109)  评论(0编辑  收藏  举报