劍指offer中的算法題(PHP版)

二維數組中的查找

在一個二維數組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。php

function search($target, $array)
{
    $i = count($array[0]) - 1;
    $j = 0;

    if ($array[count($array) - 1][$i] < $target || $array[0][0] > $target) {
        return false;
    }

    for ($i; $i >= 0; $i--) {
        if ($array[$j][$i] <= $target) {
            for ($j; $j < count($array); $j++) {
                if ($array[$j][$i] == $target) {
                    return true;
                } else if ($array[$j][$i] > $target) {
                    break;
                }
            }
        }
    }

    return false;
}


$s = [[1, 2, 8, 9], [2, 4, 9, 12], [4, 7, 10, 13], [6, 8, 11, 15]];
var_dump(search(1, $s));

替換空格

請實現一個函數,將一個字符串中的空格替換成「%20」。例如,當字符串爲We Are Happy.則通過替換以後的字符串爲We%20Are%20Happy。git

function replace($str) {
    $len = strlen($str);
    if ($len <= 0 ) {
        return false;
    }
    $blank = 0;
    for ($i = 0; $i < $len; $i++) {
        if ($str[$i] == ' ') {
            $blank++;
        }
    }
    if ($blank == 0) {
        return false;
    }

    $new_length = ($len + $blank * 2) - 1;

    for ($i = $len-1; $i >=0; $i--) {
        if ($str[$i] == ' ') {
            $str[$new_length--] = '0';
            $str[$new_length--] = '2';
            $str[$new_length--] = '%';
        } else {
            $str[$new_length--] = $str[$i];
        }
    }

    return $str;
}


var_dump(replace('We Are Happy'));

斐波那契數列

你們都知道斐波那契數列,如今要求輸入一個整數n,請你輸出斐波那契數列的第n項。解法有兩種,一種是遞歸法,一種是迭代法,可是遞歸法計算的時間複雜度是以n的指數的方式遞增的,若是面試中千萬不要用遞歸法,必定要用迭代法。面試

遞歸法算法

function a($n) {
    if ($n == 0) {
        return 0;
    } else if ($n == 1) {
        return 1;
    }

    return a($n-1) + a($n - 2);
}


echo a(10);

迭代法數組

function a($n) {

    $ret = array();

    for ($i=0; $i <= $n; $i++) {
        if ($i == 0) {
            $ret[$i] = 0;
            continue;
        }else if ($i == 1) {
            $ret[$i] = 1;
            continue;
        }

        $ret[$i] = $ret[$i-1] + $ret[$i-2];
    }

    return $ret[$n];
}

echo a(10);

調整數組順序使奇數位於偶數前面

輸入一個整數數組,實現一個函數來調整該數組中數字的順序,使得全部的奇數位於數組的前半部分,全部的偶數位於位於數組的後半部分app

function test($array) {

    if (count($array) < 2) {
        return false;
    }

    $start = 0;
    $end = count($array) - 1;

    while ($start < $end) {
        while ($array[$end] % 2 == 0 && $start < $end) {
            $end--;
        }

        while ($array[$start] % 2 == 1 && $start < $end) {
            $start++;
        }

        if ($array[$start] % 2 == 0 && $array[$end] % 2 == 1) {
            $temp = $array[$end];
            $array[$end] = $array[$start];
            $array[$start] = $temp;
        }
    }

    return $array;
}

順時針打印矩陣

輸入一個矩陣,按照從外向裏以順時針的順序依次打印出每個數字函數

這個是書上的方法oop

function printMatrixMain($data) {
    $start = 0;
    $columns = count($data);
    $rows = count($data[0]);

    while ($columns > $start * 2 && $rows > $start * 2) {
        printMatrix($data, $columns, $rows, $start);
        ++$start;
    }
}


function printMatrix($data, $columns, $rows, $start)
{
    $endx     = $columns - 1 - $start;
    $endy     = $rows - 1 - $start;

    for ($i = $start; $i <= $endx; $i++) {
        echo $data[$start][$i], '/';
    }

    for ($i = $start + 1; $i <= $endy; $i++) {
        echo $data[$i][$endx], '/';
    }

    for ($i = $endx - 1; $i >= $start; $i--) {
        echo $data[$endy][$i], '/';
    }

    for ($i = $endy - 1; $i > $start; $i--) {
        echo $data[$i][$start], '/';
    }
}


$s = array(
    array(1, 2, 3, 4, 5),
    array(5, 6, 7, 8, 9),
    array(9, 10, 11, 12, 13),
    array(13, 14, 15, 16, 17),
    array(1, 2, 3, 4, 5),
);

printMatrixMain($s);

這個是我本身寫的方法性能

function printMatrix($data)
{
    $start    = 0;
    $num      = 0;
    $can_loop = true;
    $endx     = count($data[0]) - 1;
    $endy     = count($data) - 1;

    while ($can_loop) {
        if (($endx - $num - $start < 2) || ($endy - $num - $start) < 2) {
            $can_loop = false;
        }

        for ($i = $start; $i <= $endx - $num; $i++) {
            echo $data[$start][$i], '/';
        }

        for ($i = $start + 1; $i <= $endy - $num; $i++) {
            echo $data[$i][$endx - $num], '/';
        }

        for ($i = $endx - $num - 1; $i >= $start; $i--) {
            echo $data[$endy - $num][$i], '/';
        }

        for ($i = $endy - $num - 1; $i > $start; $i--) {
            echo $data[$i][$start], '/';
        }

        $start++;
        $num++;
    }
}


$s = array(
    array(1, 2, 3, 4, 5),
    array(5, 6, 7, 8, 9),
    array(9, 10, 11, 12, 13),
    array(13, 14, 15, 16, 17),
    array(1, 2, 3, 4, 5),
);

printMatrix($s);

二叉搜索樹的後序遍歷序列

輸入一個整數數組,判斷該數組是否是某二叉搜索樹的後序遍歷的結果。若是是則輸出true,不然輸出false.指針

function VerifySquenceOfBST($data) {
    if(empty($data)){
        return false;
    }
    
    $length = count($data);
    $root   = $data[$length - 1];

    for($i = 0; $i<$length-1; $i++) {
        if($data[$i] > $root) {
            break;
        }
    }

    $j = $i;

    for($j; $j < $length -1; $j++) {
        if ($data[$j] < $root) {
            return false;
        }
    }

    $left = true;
    $right = true;

    if($i > 0) {
        $left = VerifySquenceOfBST(array_slice($data, 0, $i));
    }

    if($j < $length - 1) {
        $right = VerifySquenceOfBST(array_slice($data, $i, $length-1-$i));
    }

    return ($left&&$right);
}

var_dump(VerifySquenceOfBST([5,7,6,9,11,10,8]));

字符串的排列

輸入一個字符串,打印出全部字符串的組合,例如:abc 會打印出abc,acb bac bca cab cba

function Permutation($str) {
    if ($str == NULL)
        return false;
    if (!is_string($str))
        return false;
    echo_child($str, 0);             /*書上用指針,這裏咱們用下標*/
}

function echo_child($str, $index) {
    $len = strlen($str);
    if ($len == ($index + 1)) {
        echo $str . "    ";
        return false;
    } else {
        for ($i = $index; $i < $len; $i++) {
            $new_str         = $str;
            $tmp             = $new_str[$index];
            $new_str[$index] = $new_str[$i];
            $new_str[$i]     = $tmp;              /*以上是和第一個字符交換*/
            echo_child($new_str, $index + 1);  /*運用遞歸不斷對餘下的部分進行交換*/
        }
    }
}

Permutation('abc');

數組中出現次數超過一半的數字

數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度爲9的數組{1,2,3,2,2,2,5,4,2}。因爲數字2在數組中出現了5次,超過數組長度的一半,所以輸出2。若是不存在則輸出0。

function MoreThanHalfNum_Solution($data)
{
   if (empty($data)) {
        return false;
    }

    $ret = array();

    foreach ($data as $key => $val) {
        if (empty($ret)) {
            $ret['value'] = $val;
            $ret['count'] = 1;
        } else {
            if ($val == $ret['value']) {
                $ret['count']++;
            } else {
                if (--$ret['count'] == 0) {
                    $ret['value'] = $val;
                    $ret['count'] = 1;
                }
            }
        }
    }

    if (checkMoreThanHalf($data, $ret['value'])) {
        return $ret['value'];
    } else {
        return 0;
    }
}

function checkMoreThanHalf($data, $number) {
    $time = 0;

    foreach ($data as $key => $val) {
        if ($val == $number) {
            $time++;
        }
    }

    if ($time * 2 > count($data)) {
        return true;
    } else {
        return false;
    }
}

連續子數組的最大和

輸入一個整形數組,數組裏有正數也有負數。數組中一個或連續的多個整數組成一個子數組。求全部子數組的和的最大值。要求時間複雜度爲O(n)。

function FindGreatestSumOfSubArray($data)
{
    if (empty($data)) {
        return false;
    }

    $ret = 0;
    $max = $data[0];

    for ($i = 0; $i < count($data); $i++) {
        $ret = $ret + $data[$i];

        if ($ret > $max) {
            $max = $ret;
        }

        if ($ret < 0) {
            $ret = 0;
        }
    }

    return $max;
}

整數中1出現的次數(從1到n整數中1出現的次數)

例如輸入12,從1到12這些整數中包含1的數字有1,10,11和12,1一共出現了5次

function NumberOf1Between1AndN_Solution($str)
{
    settype($str, 'string');

    if ($str == 0 || strlen($str) == 0) {
        return 0;
    }

    $first = $str[0];

    if (strlen($str) == 1 && $first > 0) {
        return 1;
    }

    if ($first > 1) {
        $numFirstDigit = powerBase10(strlen($str) - 1);
    } else {
        $numFirstDigit = substr($str, 1) + 1;
    }

    $numOtherDigits = $first * (strlen($str)-1) * powerBase10(strlen($str)-2);
    $numRecursive = NumberOf1Between1AndN_Solution(substr($str, 1));

    return $numFirstDigit + $numOtherDigits + $numRecursive;
}

function powerBase10($number) {
    return pow(10, $number);
}

數組中只出現一次的數字

一個整型數組裏除了兩個數字以外,其餘的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。

function FindNumsAppearOnce($array) {
    if (empty($array)) {
        return false;
    }

    $xor = 0;
    foreach ($array as $key => $val) {
        $xor ^= $val;
    }

    $indexOf1 = findFirstBit1($xor);

    $result = array(0,0);
    foreach ($array as $key => $value) {
        if (isBit1($value, $indexOf1)) {
            $result[0] ^= $value;
        } else {
            $result[1] ^= $value;
        }
    }

    return $result;
}


function findFirstBit1($num) {
    $index = 0;

    while (($num & 1) == 0) {
        $num >>= 1;
        $index++;
    }

    return $index;
}

function isBit1($num, $indexBit) {
    $num >>= $indexBit;

    return (($num & 1) === 1);
}

$ret = FindNumsAppearOnce(array(2, 4, 3, 6, 3, 2,5,5));
echo $ret[0],$ret[1];

和爲S的兩個數字

輸入一個遞增排序的數組和一個數字S,在數組中查找兩個數,使得他們的和正好是S,若是有多對數字的和等於S,輸出任意一對便可。

function FindNumbersWithSum($array, $sum) {
    if (empty($array)) {
        return false;
    }

    $start = 0;
    $end   = count($array) - 1;

    while ($start < $end) {
        if ($array[$start] + $array[$end] < $sum) {
            ++$start;
        } else if ($array[$start] + $array[$end] > $sum) {
            --$end;
        } else {
            return $array[$start].'/'.$array[$end];
        }
    }

    return false;
}

圓圈中最後剩下的數字

0,1,...,n-1這n個數字排成一個圓圈,從數字0開始每次從這個圓圈裏刪除第m個數字,求出這個圓圈裏剩下的最後一個數字。

//經過總結出的公式提供的算法,公式證實過程不展開。
function LastRemaining_Solution($n, $m) {
    if ($n < 1 || $m < 1) {
        return -1;
    }

    $last = 0;

    for($i = 2; $i <= $n; $i++) {
        $last = ($last + $m) % $i;
    }

    return $last;
}



//模擬環形鏈表,這個效率和性能都不如前一個,可是思路簡單
function LastRemaining_Solution2($n, $m) {
    if ($n < 1 || $m < 1) {
        return -1;
    }

    $data = array();
    for ($i=0; $i< $n; $i++) {
        $data[] = $i;
    }

    $p = 0;
    while (count($data) >1 ) {
        for ($i=1; $i<$m; $i++) {
            ++$p;
            $p = isset($data[$p]) ? $p : 0;
        }
        unset($data[$p]);
        $data = array_values($data);
        $p = isset($data[$p]) ? $p : 0;
    }

    return reset($data);
}
相關文章
相關標籤/搜索