首頁  >  文章  >  後端開發  >  一個php的面試題,大家看看

一個php的面試題,大家看看

WBOY
WBOY原創
2016-12-05 13:44:13995瀏覽

<code class="php">$listData = [
    '111' => ['a', 'b', 'c', 'a'],
    '222' => ['d', 'e', 'f', 'f', 'b'],
    '333' => ['g', 'h'],
    '444' => ['i', 'j'],
    ...
];</code>

定義一個函數,傳入$listData
如果111裡面的元素,和222/333/444... 裡面的元素有重複,返回false
如果222裡面的元素,和111/333/444 .... 裡面的元素有重複,回傳false
如果333裡面的元素,和111/222/444... 裡面的元素有重複,回傳false
如果...

允許 111/222/333/444 自己裡面的元素重複,回傳true
其他狀況回傳true


已知:
$listData長度未知
111/222/333/444... 的長度未知
111/222/333/444... 裡的元素為字串和數字



我自己實作了一下,感覺演算法很糟,請問有沒有其他方法

<code class="php">function test ($array) {

    $tempValueList  = [];
    foreach ($array as $key => $valueList) {
        
        foreach ($valueList as $value) {
            
            $tempValueList[]    = $key . '~' . $value;
        }
    }
    $result         = true;
    foreach ($array as $key => $valueList) {
        
        foreach ($valueList as $value) {
            
            foreach ($tempValueList as $_value) {
                
                $pos    = strpos($_value, '~');
                $_key   = substr($_value, 0, $pos);
                $_val   = substr($_value, $pos + 1);

                if ($key == $_key) {

                    continue;
                }
                if ($_val == $value) {

                    $result = false;
                    break 3;
                }
            }
        }
    }

    return      $result;
}</code>

回覆內容:

<code class="php">$listData = [
    '111' => ['a', 'b', 'c', 'a'],
    '222' => ['d', 'e', 'f', 'f', 'b'],
    '333' => ['g', 'h'],
    '444' => ['i', 'j'],
    ...
];</code>

定義一個函數,傳入$listData
如果111裡面的元素,和222/333/444... 裡面的元素有重複,返回false
如果222裡面的元素,和111/333/444 .... 裡面的元素有重複,回傳false
如果333裡面的元素,和111/222/444... 裡面的元素有重複,回傳false
如果...

允許 111/222/333/444 自己裡面的元素重複,回傳true
其他狀況回傳true


已知:
$listData長度未知
111/222/333/444... 的長度未知
111/222/333/444... 裡的元素為字串和數字



我自己實作了一下,感覺演算法很糟,請問有沒有其他方法

<code class="php">function test ($array) {

    $tempValueList  = [];
    foreach ($array as $key => $valueList) {
        
        foreach ($valueList as $value) {
            
            $tempValueList[]    = $key . '~' . $value;
        }
    }
    $result         = true;
    foreach ($array as $key => $valueList) {
        
        foreach ($valueList as $value) {
            
            foreach ($tempValueList as $_value) {
                
                $pos    = strpos($_value, '~');
                $_key   = substr($_value, 0, $pos);
                $_val   = substr($_value, $pos + 1);

                if ($key == $_key) {

                    continue;
                }
                if ($_val == $value) {

                    $result = false;
                    break 3;
                }
            }
        }
    }

    return      $result;
}</code>

看了看,之前的那倆答案都是不能用的。 LZ真是苦命。 。

我對子數組的定義是像 ['a', 'b', 'c', 'a'] 這樣的單一數組。

我的答案:

<code>$result = array();
foreach ($listData as $line) {
    //子数组内部去重,再组装回原来的格式
    $result[] = array_unique($line);
}

//子数组先去重再合并的结果数量 和 先合并子数组再去重的结果数量 做比较。
//如果是相同的,意味着不存在跨子数组的重复,只存在子数组内部重复,所以`True`
var_dump(count(array_merge(...$result)) === count(array_unique(array_merge(...$listData))));</code>

我這個答案調用系統函數次數比較多,看起來簡潔一些,但是PHP array_xxx 這類函數很大一部分性能是不具備優勢的,如果不用這些函數,能相對程度提高運行效率。

目前, @springhack 的效率是最高的。而且在各種情形下都能保持最高效率。

方便理解的輔助參考資訊:

原始資料:

<code>$listData = [
    '111' => ['a', 'b', 'c', 'a'],
    '222' => ['d', 'e', 'f', 'f', 'b'],
    '333' => ['g', 'h'],
    '444' => ['i', 'j']
];
</code>

然後 $result 最終是這樣的:

<code>$listData = [
        '111' => ['a', 'b', 'c'],
        '222' => ['d', 'e', 'f', 'b'],
        '333' => ['g', 'h'],
        '444' => ['i', 'j']
];
</code>

子數組先去重再合併的結果

<code>Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => d
    [4] => e
    [5] => f
    [6] => b
    [7] => g
    [8] => h
    [9] => i
    [10] => j
)
</code>

用於和上面進行數量(數組元素數量)比較的,所謂的「先合併子數組再去重的結果」:

<code>Array
(
    [0] => a
    [1] => b
    [2] => c
    [4] => d
    [5] => e
    [6] => f
    [9] => g
    [10] => h
    [11] => i
    [12] => j
)</code>

循環一次,當前元素和其它所有元素求交集,程式碼如下:

<code>    function isExistsInOther($data)
    {
        $temp = [];
        $isExists = true;
        foreach ($data as $key=>$value) {
            $temp = $data;
            unset($temp[$key]);
            if(!$isExists) break;
            @array_walk($temp,function($v,$k) use($value,&$isExists){
                if($isExists) {
                    $intersect = array_intersect($v,$value);
                    if(!empty($intersect)) {
                        $isExists = false;
                    }
                }
            });
        }
        return $isExists;
    }
    
    $listData = [
        '111' => ['a', 'k', 'c', 'a'],
        '222' => ['d', 'e', 'f', 'f', 'b'],
        '333' => ['g', 'e'],
        '444' => ['i', 'j']
    ];
    $result = isExistsInOther($listData);
    var_dump($result);
    //true  无交集
    //false 有交集</code>

<code>/**
 * [checkRepeat 检查每个key的数组值是否与其它的有重复值]
 * @param  [type] $listData [检查的数组]
 * @return [type]           [array]
 */
function checkRepeat($listData) {
    foreach($listData as $key =>$val) {
        $check_arr = $listData;
        // 删除当前key
        unset($check_arr[$key]);
        // 合并删除后的数组
        $check_arr = array_merge(...$check_arr);
        // 判断是否存在交集
        $rs[$key] = count(array_intersect($val, $check_arr)) > 0 ? false : true ;
    }
    return $rs;
}

$listData = [
    '111' => ['a', 'b', 'c', 'a'],
    '222' => ['d', 'e', 'f', 'f', 'b'],
    '333' => ['g', 'h'],
    '444' => ['i', 'j'],

];
$rs = checkRepeat($listData);</code>

<code>function check($arr)
{
  $chk = [];
  foreach ($arr as $k => $v)
    foreach ($v as $i)
    {
      if (isset($chk[$i] && $chk[$i] != $k)
        return false;
      $chk[$i] = $k;
    }
  return true;
}</code>

爪機碼字,應該是效率最高的,自己調試下。

既然上面都給了答案,我給你補充一下,多維數組去重

<code>/**
 * 多维数组去重
 * @param array 
 * @return array
 */
function super_unique($array)
{
    $result = array_map("unserialize", array_unique(array_map("serialize", $array)));

    foreach ($result as $key => $value)
    {
        if ( is_array($value) ) {
            $result[$key] = super_unique($value);
        }
    }

    return $result;
}</code>

多維數組去重

<code>$listData = array_values($listData);
foreach ($listData as $k => $v) {
    foreach ($listData as $n => $m) {
        if($k == $n) continue;
        if(array_intersect($v , $m)){
            echo $k.$n.'false <br>';
        }
        else{
            echo $k.$n.'true <br>';
        }
    }
}</code>

我的答案(原理:循環求交集):

<code><?php
$list = [
    '111' => ['a', 'b', 'c', 'a'],
    '222' => ['d', 'e', 'f', 'f','b'],
    '333' => ['g', 'h','c'],
    '444' => ['i', 'j']
];
function jiaoji($array){
    $listData = array_values($array);
    $list = [];
    for ($i = 0; $i < count($listData); $i++) {
        for ($j = $i+1; $j < count($listData); $j++) {
            $list[] = array_intersect($listData[$i],$listData[$j]);
        }
    }
    $result = array_filter($list);
    return count($result)==0;
}
var_dump(jiaoji($list));//bool(false)
?></code>

能不能這樣理解 只要這個數組裡面的值相互之間有交集 那就回傳false 。 。 。
array_intersect()函數好像可以用。但是問題就是將一個陣列裡面的值變成小數組傳值。

<code><?php
$listData = [
    '111' => ['a', 'b', 'c', 'a'],
    '222' => ['d', 'e', 'f', 'f', 'b'],
    '333' => ['g', 'h'],
    '444' => ['i', 'j'],
    ...
];

function getArr($listData){
    $isUnsetFirstKey = false;
    $len = count($listData);
    if($len<=1) return false;
    $firstKey = key($listData);
    $firstArr = array_unique($listData[$firstKey]);
    $newList = $listData;
    unset($newList[$firstKey]);
    foreach ($newList as $key => $val) {
        $arr = array_unique($val);
        $newarr = array_merge($firstArr,$arr);
        if(count($newarr) != count(array_unique($newarr))){
            $isUnsetFirstKey = true;
            unset($newList[$key]);
            echo $key . "<br>";
        }
    }
    if($isUnsetFirstKey) echo $firstKey . "<br>";
    getArr($newList);
}

getArr($listData);
?></code>

我的答案,看看吧,很厲害的

一維數組和二維數組類似, 在內部做判斷, 下面是二維數組的方法, 一維數組略過
比較數組合併之前和之後(之後取unique)的數組長度

<code class="php">function check_repeat($arr){
    $after_arr = [];
    // 对比自身
    foreach($arr as $index => $value){
        $arr[$index] = $after_arr = array_unique($value);
        if(count($value) !== count($after_arr)){
            return true;
        }
    }
    // 对比其他
    $temp = array_shift($arr);
    $cnt  = count($temp);
    foreach ($arr as $index => $value) {
        $cnt += count($value);
        $temp = array_merge($temp, $value);
    }

    return $cnt !== count(array_unique($temp)) ? true : false;
}

$listData = [
    '111' => ['a', 'b', 'c',],
    '222' => ['d', 'e', 'f',],
    '333' => ['g', 'h'],
    '444' => ['i', 'j'],
];

var_dump(check_repeat($listData));
</code>

<code>function test($listData) {
    $result = array_map('array_unique', $listData);
    foreach ($result as $key => $value) {
        $keys = array_values(array_diff(array_keys($result),[$key]));
        for($i = 0; $i <= count($keys); $i ++) {
            $data = array_merge_recursive($data,$result[$keys[$i]]);
            if ($i == (count($keys) -1) ) {
                $res = array_intersect($value, $data);
            }
        }
        $data = [];
    }
    return !empty($res) === true ? false : true;
}</code>

<code><?php

$listData = [
    '111' => ['a', 'b', 'c', 'a'],
    '222' => ['d', 'e', 'f', 'f', 'b'],
    '333' => ['g', 'h'],
    '444' => ['i', 'j'],
];

$temp = array();
foreach ($listData as $key => $xxx) {
    foreach ($xxx as $value) {
        if (in_array($value, $temp)) {
            echo $value.' from '.$key.' is in array';
            exit();
        }
    }
    $temp = array_merge($temp, $xxx);
}
echo 'You should get a True!';
</code>

没几行,满足需求。

一個php的面試題,大家看看

还原之前那个
shiji 的答案

先array_pop,取出最后一项。再取items数组的并集。if并集与最后一项有交集则返回true(表重复)。循环执行。

根据 @大呜 的算法改良了一下。

<code>function checkRepeat2($listData)
{
    $check_arr = $listData;
    foreach ($listData as $key => $val) {
        //之前比较过的key无需再比较
        unset($check_arr[$key]);
        if ($check_arr) {
            // 合并删除后的数组,判断是否存在交集
            //As PHP 5.6 you can use array_merge + "splat" operator to reduce a bidimensonal array to a simple array:
            if (array_intersect($val, array_merge(...$check_arr))) {
                return false;
            }
        }
    }
    return true;
}</code>

不知道是不是这样:

<code>$new_arr = [];
foreach ($listData as $key => $value) {
    foreach ($value as $k => $v) {
        $kv = $k . $v;
        if (in_array($kv, $new_arr)) {
            echo '有重复';exit;
        } else {
            $new_arr[] = $kv;
        }
    }
}</code>
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn