面试题: 判断字符串是否在另一个字符串中存在?
面试时发现好多人回答不好, 所以就梳理了一下已知的方法, 此文较长, 需要耐心的看下去。从实现和算法原理两方面解此问题, 其中有用PHP原生方法实现也有一些业界大牛创造的算法。
实现
方法一: 语言特性-内置函数
/* strpos示例 */
// test
echo 'match:', strpos('xasfsdfbk', 'xasfsdfbk') !== false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', strpos('xasfsdfbk', 'fbk') !== false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', strpos('xasfsdfbk', 'xs') != false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', strpos('xasfsdfbk', 'sfs') !== false ? 'true' : 'false', ';', PHP_EOL;
// code
strpos('xasfsdfbk', 'sfs');
// mb* 相关的函数也可, 比如说mb_strpos是基于字符数执行一个多字节安全的 strpos() 操作。
函数
描述
版本
查找字符串首次出现的位置
PHP 4, PHP 5, PHP 7
查找字符串首次出现的位置(不区分大小写)
PHP 5, PHP 7
计算指定字符串在目标字符串中最后一次出现的位置
PHP 4, PHP 5, PHP 7
计算指定字符串在目标字符串中最后一次出现的位置(不区分大小写)
PHP 5, PHP 7
查找字符串在另一个字符串中首次出现的位置
PHP 4 >= 4.0.6, PHP 5, PHP 7
查找字符串的首次出现
PHP 4, PHP 5, PHP 7
strstr() 函数的忽略大小写版本
PHP 4, PHP 5, PHP 7
计算字串出现的次数
PHP 4, PHP 5, PHP 7
方法二: 语言特性-正则匹配
// test
echo 'match:', str_match('xasfsdfbk', 'xasfsdfbk') !== false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'fbk') !== false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'xs') != false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'sfs') !== false ? 'true' : 'false', ';', PHP_EOL;
// code
function str_match($a, $b) {
return preg_match('/' . $b . '/i', $a, $matchs) ? true : false;
}
函数
描述
版本
执行匹配正则表达式
PHP 4, PHP 5, PHP 7
执行一个全局正则表达式匹配
PHP 4, PHP 5, PHP 7
方法三: 语言特性-字符串分割
// test
echo 'match:', str_match('xasfsdfbk', 'xasfsdfbk') !== false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'fbk') !== false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'xs') != false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'sfs') !== false ? 'true' : 'false', ';', PHP_EOL;
// code
function str_match($a, $b) {
return count(explode($b, $a)) >= 2 ? true : false;
}
// strtok 可以么?
// 在分割字符串时,split()与explode()谁快?
函数
描述
版本
标记分割字符串
PHP 4, PHP 5, PHP 7
使用一个字符串分割另一个字符串
PHP 4, PHP 5, PHP 7
用正则表达式将字符串分割到数组中
PHP 4, PHP 5
使用正则表达式分割多字节字符串
PHP 4 >= 4.2.0, PHP 5, PHP 7
通过一个正则表达式分隔字符串
PHP 4, PHP 5, PHP 7
方法四: 很暴力的查找
// test
echo 'match:', str_match('xasfsdfbk', 'xasfsdfbk') !== -1 ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'fbk') !== -1 ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'xs') !== -1 ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'sfs') !== -1 ? 'true' : 'false', ';', PHP_EOL;
// code
function str_match($a, $b) {
if($a == $b) {
return 0;
}
$aArr = str_split($a);
$bArr = str_split($b);
$aLen = count($aArr);
$bLen = count($bArr);
if($bLen > $aLen) {
return -1;
}
$data = [];
$aLastIndex = -1;
$bStartIndex = 0;
for($ai = 0; $ai < $aLen; $ai++) {
$av = $aArr[$ai];
$exists = false;
for($bi = $bStartIndex; $bi < $bLen; $bi++) {
$bv = $bArr[$bi];
if(($aLastIndex == -1 || $ai == ($aLastIndex + 1)) && $av == $bv) {
$exists = true;
break;
}
if ($aLastIndex != -1 && $ai == ($aLastIndex + 1) && $av != $bv) {
break;
}
}
if ($exists) {
$aLastIndex = $ai;
$bStartIndex = $bi + 1;
array_push($data, [
'value' => $av,
'index' => $ai
]);
} else {
$aLastIndex = -1;
$bStartIndex = 0;
$data = [];
}
if ($exists && $bLen == $bStartIndex) {
break;
}
}
if(!empty($data) && count($data) == $bLen) {
$begin = array_shift($data);
return $begin['index'];
} else {
return -1;
}
}
方法五: 朴素算法(暴力查找)
// demo
echo 'match:', str_match('xasfsdfbk', 'xasfsdfbk') !== false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'fbk') !== false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'xs') != false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', str_match('xasfsdfbk', 'sfs') !== false ? 'true' : 'false', ';', PHP_EOL;
// code
function str_match($a, $b) {
$aArr = str_split($a);
$bArr = str_split($b);
$aLen = count($aArr);
$bLen = count($bArr);
for ($ai = 0; $ai <= $aLen - $bLen; $ai++) {
for ($bi = 0; $bi < $bLen; $bi++) {
if($aArr[$ai + $bi] != $bArr[$bi]) {
break;
}
}
if($bLen == $bi) {
return $ai;
}
}
return false;
}
方法六: 字符串查找算法-Rabin-Karp算法
#include
#include
using namespace std;
#define BASE 256
#define MODULUS 101
void RabinKarp(char t[], char p[])
{
int t_len = strlen(t);
int p_len = strlen(p);
// 哈希滚动之用
int h = 1;
for (int i = 0; i < p_len - 1; i++)
h = (h * BASE) % MODULUS;
int t_hash = 0;
int p_hash = 0;
for (int i = 0; i < p_len; i++)
{
t_hash = (BASE * t_hash + t[i]) % MODULUS;
p_hash = (BASE * p_hash +