一道單鏈表題引起的思考

最近在刷leetCode,遇到兩道原理相近的題,以爲十分有趣和典型,經過思考和借鑑其餘coder寫法發現了新的smellphp

 

先從簡單的那道題聊起,原題是這樣描述了:java

 

給定兩個字符串形式的非負整數 num1 num2 ,計算它們的和。node

 注意:c++

 

num1 num2 的長度都小於 5100.編程

num1 num2 都只包含數字 0-9.性能

num1 num2 都不包含任何前導零。this

你不能使用任何內建 BigInteger 庫, 也不能直接將輸入的字符串轉換爲整數形式。spa

 

舉個具體例子:code

輸入  : "10",orm

          "10"

 

輸出  : 」20"

 

拿着這個題,第一反應就是想利用php的靈活性搞點黑魔法的實現。由於php的弱類型,字符串和數字之間的轉換不要太酸爽,因而秒寫出了下面的解法1:

 

function addStrings($num1, $num2) {
    $num3= $num1 + $num2;
    return (string)$num3;
}

 

這也太簡單了吧?

固然不可能這麼容易,由於會遇到$num1$num2太大,出現諸以下面的輸出報錯:

這就涉及到大int相加的進位問題,關於這個問題參考別人的實現以下:

function bigDataAdd($a,$b) {
    $m = strlen($a);
    $n = strlen($b);
    $num = $m>$n?$m:$n;//取最長數進行循環相加和進位
    $result = '';//結果
    $flag = 0; //進位標誌
    while($num--){
        $t1 = 0;//用來存儲當前位加數
        $t2 = 0;//用來存儲當前位被加數
        if($m>0){
            $t1 = $a[--$m];
        }
        if($n>0){
            $t2 = $b[--$n];
        }
        $t = $t1+$t2+$flag;//當前位加法運算考慮上一輪的進位標誌
        $flag = intval($t/10);//本輪是否進位
        $result = ($t%10).$result;//向高位添加結果
    }
    //最高位加完發現還有進位標誌,須要再向最高位+1
    if ($flag) {
        $result = $flag.$result;
    }
    return $result;
}

循環進位相加,最後完成大int相加。

因此初版的代碼改成:

 

function addStrings($num1, $num2) {
    $num3= bigDataAdd($num1, $num2);
    return (string)$num3;
}

 

這種思路就是:將兩個非負數字符串當成整型相加,而後直接轉字符串返回結果。惟一要特別處理的就是大int相加進位的問題。

 

仔細想一想,這道題從出題人的角度可能並非只想利用php的特性,畢竟最開始能使用的實現語言並無php,要考慮其餘編程語法的實現(java,c++,c),可見這道題正統解法應是他法。

另一種解法就是要把字符串的每個下標進行遍歷相加,處理好進位問題。

因此咱們須要用一個進位符$carry去記錄每次是否進位,而後也利用它來存儲每次遍歷中的臨時結果。

大概的思路:

分別去倒序遍歷$num1$num2,處理好進位,而後再返回最後結果(reverse).

具體的實現是:

 

unction addStrings($num1, $num2) {
    $carry = 0;
    $i = strlen($num1) - 1;
    $j = strlen($num2) - 1;
    $return_str = '';
    
    while($i >=0 || $j >= 0 || $carry != 0) {
        if ($i >= 0) {
            $carry += $num1[$i] + 0;
            $i--;
        }
        if ($j >= 0) {
            $carry += $num2[$j] + 0;
            $j--;
        }
        $return_str .= (string)($carry % 10);
        $carry = floor($carry / 10);
    }
    return strrev($return_str);
}

 

這就是解法二,性能和耗時都蠻不錯的:戰勝了94%的php用戶。

若是再抽象一下咱們的入參,其實字符串也是一種單鏈表的具體實現。因此也能夠將字符串封裝成ListNode(簡單的單鏈表)。其餘思路和上面是同樣的,只是將遍歷兩個字符串變成遍歷兩個鏈表。

具體以下:

 

class NewSolution {
    public function addTowStrings($num1, $num2) {
        $list1 = null;
        $list2 = null;
        // 構建list1
        $length1 = strlen($num1);
        $length2 = strlen($num2);

        $list1 = $this->makeStringToListNode(strrev($num1));
        $list2 = $this->makeStringToListNode(strrev($num2));
        $q = $list1;
        $p = $list2;
        $carry = 0;

        $dummyNode = new ListNode(0);
        $currentNode = $dummyNode;
        $newNode = $currentNode;
        while($q != null || $p != null || $carry != 0) {
            //print_r("come here");
            // 遍歷兩個鏈表
            if ($q != null) {
                $carry += $q->val;
            }
            if ($p != null) {
                $carry += $p->val;
            }
            $sum = $carry % 10;

            $currentNode->next = new ListNode($sum);

            $currentNode = $currentNode->next;

            $carry = floor($carry / 10);
            if ($q != null) {
                $q = $q->next;

            }
            if ($p != null) {
                $p = $p->next;
            }
        }

        $realNewNode = $newNode->next;

        $result = "";
        while($realNewNode != null) {
            $result .= (string) $realNewNode->val;
            $realNewNode = $realNewNode->next;
        }

        return strrev($result);

    }
    public function makeStringToListNode($string) {
        $length = strlen($string);
        // 啞節點
        $dummyNode = new ListNode(0);
        $currentNode=  $dummyNode;
        $return_node = $currentNode;
        for ($i = 0; $i < $length; $i++) {
            $currentNode->next = new ListNode($string[$i]);
            $currentNode = $currentNode->next;
        }

        return $return_node->next;
    }
}

$s = new NewSolution();
$str = $s->addTowStrings("13002", "11");

 

這種寫法比較學院派了,性能和內存使用都是很是差的。

因此刷題既要保證能get到核心考點,又要兼顧性能才行。而php的確由於過於自由化致使咱們可能會深陷到dark magic的marsh。請提升警戒,也不忘初心!

 

相關文章
相關標籤/搜索