/**
* PHP字符串“異或”算法
* param array key
* @param Request $request
* @return mixed|string|void
*/
public function setSecretKey(Request $request){
$keyArr = $request->input('key');
if(!is_array($keyArr) || empty($keyArr))
return;
foreach ($keyArr as $v){
if(empty($v) || (strlen($v) != 32)){
return;
}
}
if(count($keyArr) == 1)
return $keyArr[0];
$arrLength = count($keyArr);
$initKey = "00000000000000000000000000000000";
$initKeyArr = str_split($initKey);
for($i = 0;$i < $arrLength;$i++){
$newKey = '';
for($j = 0;$j < strlen($keyArr[$i]);$j++){
$str = '';
$tmpArr = str_split($keyArr[$i]);
$tmpA = str_pad(base_convert($tmpArr[$j],16,2),4,0,STR_PAD_LEFT);
$tmpB = str_pad(base_convert($initKeyArr[$j],16,2),4,0,STR_PAD_LEFT);
for($k=0;$k<strlen($tmpA);$k++){
$str .=(intval($tmpA[$k]) ^ intval($tmpB[$k]));
}
$tmpOneKey = strtoupper(base_convert($str,2,16));
unset($str);
$newKey .= $tmpOneKey;
}
unset($initKeyArr);
$initKeyArr = str_split($newKey);
}
return join($initKeyArr);
}
主要是聊基礎(chǔ)算法知識和代碼題。
算法簡單,而且效率高,每次可以操作8個字節(jié)的數(shù)據(jù),加密解密的KEY為16字節(jié),即包含4個int數(shù)據(jù)的int型數(shù)組,加密輪數(shù)應(yīng)為8的倍數(shù),一般比較常用的輪數(shù)為64,32,16,QQ原來就是用TEA16來還原密碼的. TEA算法 核心為: PHP部分代碼非我原創(chuàng),大家可以了解一下這方面的知識 上面的是TEA的算法,XTEA的算法為: #include
又到安利Python的時間, 最終代碼不超過30行(優(yōu)化前),加上優(yōu)化也不過40行。
第一步. 構(gòu)造Trie(用dict登記結(jié)點(diǎn)信息和維持子結(jié)點(diǎn)集合):
-- 思路:對詞典中的每個單詞,逐詞逐字母拓展Trie,單詞完結(jié)處的結(jié)點(diǎn)用None標(biāo)識。
def make_trie(words):
trie = {}
for word in words:
t = trie
for c in word:
if c not in t: t[c] = {}
t = t[c]
t[None] = None
return trie
第二步. 容錯查找(容錯數(shù)為tol):
-- 思路:實(shí)質(zhì)上是對Trie的深度優(yōu)先搜索,每一步加深時就消耗目標(biāo)詞的一個字母。當(dāng)搜索到達(dá)某個結(jié)點(diǎn)時,分為不消耗容錯數(shù)和消耗容錯數(shù)的情形,繼續(xù)搜索直到目標(biāo)詞為空。搜索過程中,用path記錄搜索路徑,該路徑即為一個詞典中存在的詞,作為糾錯的參考。
-- 最終結(jié)果即為諸多搜索停止位置的結(jié)點(diǎn)路徑的并集。
def check_fuzzy(trie, word, path='', tol=1):
if word == '':
return {path} if None in trie else set()
else:
p0 = set()
if word[0] in trie:
p0 = check_fuzzy(trie[word[0]], word[1:], path+word[0], tol)
p1 = set()
if tol > 0:
for k in trie:
if k is not None and k != word[0]:
p1.update(check_fuzzy(trie[k], word[1:], path+k, tol-1))
return p0 | p1
簡單測試代碼 ------
構(gòu)造Trie:
words = ['hello', 'hela', 'dome']
t = make_trie(words)
In [11]: t
Out[11]:
{'d': {'o': {'m': {'e': {'$': {}}}}},
'h': {'e': {'l': {'a': {'$': {}}, 'l': {'o': {'$': {}}}}}}}
容錯查找:
In [50]: check_fuzzy(t, 'hellu', tol=0)
Out[50]: {}
In [51]: check_fuzzy(t, 'hellu', tol=1)
Out[51]: {'hello'}
In [52]: check_fuzzy(t, 'healu', tol=1)
Out[52]: {}
In [53]: check_fuzzy(t, 'healu', tol=2)
Out[53]: {'hello'}
似乎靠譜~
---------------------------分--割--線--------------------------------------
以上是基于Trie的approach,另外的approach可以參看@黃振童鞋推薦Peter Norvig即P神的How to Write a Spelling Corrector
雖然我已有意無意模仿P神的代碼風(fēng)格,但每次看到P神的源碼還是立馬跪...
話說word[1:]這種表達(dá)方式其實(shí)是有淵源的,相信有的童鞋對(cdr word)早已爛熟于心...(呵呵
------------------------分-----割-----線-----二--------------------------------------
回歸正題.....有童鞋說可不可以增加新的容錯條件,比如增刪字母,我大致對v2方法作了點(diǎn)拓展,得到下面的v3版本。
拓展的關(guān)鍵在于遞歸的終止,即每一次遞歸調(diào)用必須對參數(shù)進(jìn)行有效縮減,要么是參數(shù)word,要么是參數(shù)tol~
def check_fuzzy(trie, word, path='', tol=1):
if tol < 0:
return set()
elif word == '':
results = set()
if None in trie:
results.add(path)
# 增加詞尾字母
for k in trie:
if k is not None:
results |= check_fuzzy(trie[k], '', path+k, tol-1)
return results
else:
results = set()
# 首字母匹配
if word[0] in trie:
results |= check_fuzzy(trie[word[0]], word[1:], path + word[0], tol)
# 分情形繼續(xù)搜索(相當(dāng)于保留待探索的回溯分支)
for k in trie:
if k is not None and k != word[0]:
# 用可能正確的字母置換首字母
results |= check_fuzzy(trie[k], word[1:], path+k, tol-1)
# 插入可能正確的字母作為首字母
results |= check_fuzzy(trie[k], word, path+k, tol-1)
# 跳過余詞首字母
results |= check_fuzzy(trie, word[1:], path, tol-1)
# 交換原詞頭兩個字母
if len(word) > 1:
results |= check_fuzzy(trie, word[1]+word[0]+word[2:], path, tol-1)
return results
好像還是沒有過30行……注釋不算(
本答案的算法只在追求極致簡潔的表達(dá),概括問題的大致思路。至于實(shí)際應(yīng)用的話可能需要很多Adaption和Tuning,包括基于統(tǒng)計(jì)和學(xué)習(xí)得到一些詞語校正的bias。我猜測這些拓展都可以反映到Trie的結(jié)點(diǎn)構(gòu)造上面,比如在結(jié)點(diǎn)處附加一個概率值,通過這個概率值來影響搜索傾向;也可能反映到更多的搜索分支的控制參數(shù)上面,比如增加一些更有腦洞的搜索分支。(更細(xì)節(jié)的問題這里就不深入了逃
----------------------------------分-割-線-三----------------------------------------
童鞋們可能會關(guān)心時間和空間復(fù)雜度的問題,因?yàn)樯鲜鲞@種優(yōu)(cu)雅(bao)的寫法會導(dǎo)致產(chǎn)生的集合對象呈指數(shù)級增加,集合的合并操作時間也指數(shù)級增加,還使得gc不堪重負(fù)。而且,我們并不希望搜索算法一下就把所有結(jié)果枚舉出來(消耗的時間亦太昂貴),有可能我們只需要搜索結(jié)果的集合中前三個結(jié)果,如果不滿意再搜索三個,諸如此類...
那腫么辦呢?................是時候祭出yield小魔杖了? ??)ノ
下述版本姑且稱之為lazy,看上去和v3很像(其實(shí)它倆在語義上是幾乎等同的
def check_lazy(trie, word, path='', tol=1):
if tol < 0:
pass
elif word == '':
if None in trie:
yield path
# 增加詞尾字母
for k in trie:
if k is not None:
yield from check_lazy(trie[k], '', path + k, tol - 1)
else:
if word[0] in trie:
# 首字母匹配成功
yield from check_lazy(trie[word[0]], word[1:], path+word[0], tol)
# 分情形繼續(xù)搜索(相當(dāng)于保留待探索的回溯分支)
for k in trie:
if k is not None and k != word[0]:
# 用可能正確的字母置換首字母
yield from check_lazy(trie[k], word[1:], path+k, tol-1)
# 插入可能正確的字母作為首字母
yield from check_lazy(trie[k], word, path+k, tol-1)
# 跳過余詞首字母
yield from check_lazy(trie, word[1:], path, tol-1)
# 交換原詞頭兩個字母
if len(word) > 1:
yield from check_lazy(trie, word[1]+word[0]+word[2:], path, tol-1)
不借助任何容器對象,我們近乎聲明式地使用遞歸子序列拼接成了一個序列。
[新手注釋] yield是什么意思呢?就是程序暫停在這里了,返回給你一個結(jié)果,然后當(dāng)你調(diào)用next的時候,它從暫停的位置繼續(xù)走,直到有下個結(jié)果然后再暫停。要理解yield,你得先理解yield... Nonono,你得先理解iter函數(shù)和next函數(shù),然后再深入理解for循環(huán),具體內(nèi)容童鞋們可以看官方文檔。而yield from x即相當(dāng)于for y in x: yield y。
給剛認(rèn)識yield的童鞋一個小科普,順便回憶一下組合數(shù)C(n,m)的定義即
C(n, m) = C(n-1, m-1) + C(n-1, m)
如果我們把C視為根據(jù)n和m確定的集合,加號視為并集,利用下面這個generator我們可以懶惰地逐步獲取所有組合元素:
def combinations(seq, m):
if m > len(seq):
raise ValueError('Cannot choose more than sequence has.')
elif m == 0:
yield ()
elif m == len(seq):
yield tuple(seq)
else:
for p in combinations(seq[1:], m-1):
yield (seq[0],) + p
yield from combinations(seq[1:], m)
for combi in combinations('abcde', 2):
print(combi)
可以看到,generator結(jié)構(gòu)精準(zhǔn)地反映了集合運(yùn)算的特征,而且蘊(yùn)含了對元素進(jìn)行映射的邏輯,可讀性非常強(qiáng)。
OK,代碼到此為止。利用next函數(shù),我們可以懶惰地獲取查找結(jié)果。
In [54]: words = ['hell', 'hello', 'hela', 'helmut', 'dome']
In [55]: t = make_trie(words)
In [57]: c = check_lazy(t, 'hell')
In [58]: next(c)
Out[58]: 'hell'
In [59]: next(c)
Out[59]: 'hello'
In [60]: next(c)
Out[60]: 'hela'
話說回來,lazy的一個問題在于我們不能提前預(yù)測并剔除重復(fù)的元素。你可以采用一個小利器decorator,修飾一個generator,保證結(jié)果不重復(fù)。
from functools import wraps
def uniq(func):
@wraps(func)
def _func(*a, **kw):
seen = set()
it = func(*a, **kw)
while 1:
x = next(it)
if x not in seen:
yield x
seen.add(x)
return _func
這個url打開的文件包含常用英語詞匯,可以用來測試代碼:
In [10]: import urllib
In [11]: f = urllib.request.urlopen("https://raw.githubusercontent.com/eneko/data-repository/master/data/words.txt")
# 去除換行符
In [12]: t = make_trie(line.decode().strip() for line in f.readlines())
In [13]: f.close()
----------------------分-割-線-四-----------------------------
最后的最后,Python中遞歸是很昂貴的,但是遞歸的優(yōu)勢在于描述問題。為了追求極致性能,我們可以把遞歸轉(zhuǎn)成迭代,把去除重復(fù)的邏輯直接代入進(jìn)來,于是有了這個v4版本:
from collections import deque
def check_iter(trie, word, tol=1):
seen = set()
q = deque([(trie, word, '', tol)])
while q:
trie, word, path, tol = q.popleft()
if word == '':
if None in trie:
if path not in seen:
seen.add(path)
yield path
if tol > 0:
for k in trie:
if k is not None:
q.appendleft((trie[k], '', path+k, tol-1))
else:
if word[0] in trie:
q.appendleft((trie[word[0]], word[1:], path+word[0], tol))
if tol > 0:
for k in trie.keys():
if k is not None and k != word[0]:
q.append((trie[k], word[1:], path+k, tol-1))
q.append((trie[k], word, path+k, tol-1))
q.append((trie, word[1:], path, tol-1))
if len(word) > 1:
q.append((trie, word[1]+word[0]+word[2:], path, tol-1))
可以看到,轉(zhuǎn)為迭代方式后我們?nèi)匀豢梢宰畲蟪潭缺A暨f歸風(fēng)格的程序形狀,但也提供了更強(qiáng)的靈活性(對于遞歸,相當(dāng)于我們只能用棧來實(shí)現(xiàn)這個q)?;谶@種迭代程序的結(jié)構(gòu),如果你有詞頻數(shù)據(jù),可以用該數(shù)據(jù)維持一個最優(yōu)堆q,甚至可以是根據(jù)上下文自動調(diào)整詞頻的動態(tài)堆,維持高頻詞匯在堆頂,為詞語修正節(jié)省不少性能。這里就不深入了。
【可選的一步】我們在對單詞進(jìn)行糾正的時候往往傾向于認(rèn)為首字母是無誤的,利用這個現(xiàn)象可以減輕不少搜索壓力,花費(fèi)的時間可以少數(shù)倍。
def check_head_fixed(trie, word, tol=1):
for p in check_lazy(trie[word[0]], word[1:], tol=tol):
yield word[0] + p
最終我們簡單地benchmark一下:
In [18]: list(check_head_fixed(trie, 'misella', tol=2))
Out[18]:
['micellar',
'malella',
'mesilla',
'morella',
'mysell',
'micelle',
'milla',
'misally',
'mistell',
'miserly']
In [19]: %timeit list(check_head_fixed(trie, 'misella', tol=2))
1.52 ms ± 2.84 μs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
在Win10的i7上可以在兩毫秒左右返回所有結(jié)果,可以說令人滿意。
在當(dāng)今數(shù)字化時代,大數(shù)據(jù)已成為各行各業(yè)不可忽視的重要資產(chǎn)。對于數(shù)據(jù)科學(xué)家和數(shù)據(jù)分析師來說,掌握大數(shù)據(jù)算法是至關(guān)重要的技能之一。隨著數(shù)據(jù)量的不斷增長和復(fù)雜性的提升,大數(shù)據(jù)算法的應(yīng)用范圍也越來越廣泛。
大數(shù)據(jù)算法是指為處理大規(guī)模數(shù)據(jù)而設(shè)計(jì)的一組算法和技術(shù)。在處理海量數(shù)據(jù)時,傳統(tǒng)的算法可能無法有效地運(yùn)行,因此需要專門針對大數(shù)據(jù)量級和特點(diǎn)設(shè)計(jì)的算法來進(jìn)行處理。
大數(shù)據(jù)算法的重要性在于它可以幫助企業(yè)從海量數(shù)據(jù)中提取出有用的信息、模式和見解,為決策提供支持。通過運(yùn)用大數(shù)據(jù)算法,企業(yè)可以更好地理解客戶需求、優(yōu)化產(chǎn)品設(shè)計(jì)、改進(jìn)營銷策略,從而提升競爭力。
下面列舉了一些常見的大數(shù)據(jù)算法面試題,希望能夠幫助準(zhǔn)備面試的同學(xué)更好地理解和掌握相關(guān)知識:
為了更好地準(zhǔn)備大數(shù)據(jù)算法面試,以下是一些建議:
大數(shù)據(jù)算法在當(dāng)今信息爆炸的時代扮演著至關(guān)重要的角色,對于從事數(shù)據(jù)分析和數(shù)據(jù)科學(xué)相關(guān)工作的人員來說,掌握大數(shù)據(jù)算法是必備的技能之一。通過不斷學(xué)習(xí)、實(shí)踐和應(yīng)用,相信每個人都可以在大數(shù)據(jù)算法領(lǐng)域取得優(yōu)異的成績。
PHP一直是Web開發(fā)領(lǐng)域中備受推崇的編程語言之一,許多公司在招聘開發(fā)人員時都會考察候選人的PHP技能。因此,掌握一些常見的PHP面試題是非常重要的。無論您是準(zhǔn)備面試,還是想進(jìn)一步加深對PHP的理解,本文將為您提供一些從初級到高級的PHP面試題,幫助您在面試中脫穎而出。
1. 什么是PHP? PHP即“Hypertext Preprocessor”的縮寫,是一種開源的服務(wù)器端腳本語言,適用于Web開發(fā)和可嵌入中使用。PHP腳本在服務(wù)器端運(yùn)行,生成HTML輸出到客戶端瀏覽器。
2. PHP的特點(diǎn)有哪些? PHP具有許多特點(diǎn),包括開源、跨平臺、易學(xué)易用、功能強(qiáng)大、支持多種數(shù)據(jù)庫等。PHP的靈活性和擴(kuò)展性使其成為許多開發(fā)人員的首選語言之一。
3. 如何在PHP中輸出文本?
在PHP中,您可以使用echo或print語句來輸出文本。例如,您可以使用echo "Hello, World!";
來輸出“Hello, World!”。
1. 什么是PHP中的變量作用域? 在PHP中,變量的作用域指的是變量在腳本中可見的區(qū)域。PHP具有四種不同的作用域:局部作用域、全局作用域、靜態(tài)作用域和超全局作用域。
2. 如何包含一個文件到PHP頁面中? 您可以使用include或require語句包含一個文件到PHP頁面中。區(qū)別在于如果文件不存在,include會發(fā)出警告并繼續(xù)執(zhí)行腳本,而require會發(fā)出致命錯誤并停止腳本執(zhí)行。
3. 什么是PHP中的SESSION? SESSION是一種將用戶信息存儲在服務(wù)器上的方法,在用戶訪問您的站點(diǎn)時創(chuàng)建。PHP中的SESSION通過一個唯一的SESSION ID來識別每個用戶,并將數(shù)據(jù)存儲在服務(wù)器的內(nèi)存中。
1. 什么是PHP的自動加載? PHP的自動加載功能允許您在類被實(shí)例化或類被調(diào)用時自動加載類文件。這樣可以提高代碼的模塊化和靈活性,避免手動包含大量的類文件。
2. 什么是PHP中的命名空間? PHP的命名空間是一種將類、函數(shù)和常量組織到更合理和更具可讀性的結(jié)構(gòu)中的方式。通過命名空間,可以避免命名沖突,提高代碼的可維護(hù)性。
3. 什么是PHP中的trait? Trait是PHP中一種代碼復(fù)用的機(jī)制,它類似于類的一個部分,可以在不同類之間復(fù)用方法集。Trait提供了一種更優(yōu)雅的代碼組織方式,避免多重繼承的復(fù)雜性。
通過以上PHP面試題的介紹,相信您對PHP的知識有了更深入的了解,也為您在面試中展現(xiàn)出色的機(jī)會提供了幫助。繼續(xù)學(xué)習(xí)和提升自己的PHP技能,相信您一定能在職業(yè)道路上獲得更多的成就!
在軟件開發(fā)領(lǐng)域,掌握算法是每個程序員成為頂尖開發(fā)人員所必備的技能之一。無論你是初學(xué)者還是有經(jīng)驗(yàn)的PHP開發(fā)人員,提升自己的算法技能都是一個持續(xù)學(xué)習(xí)和發(fā)展的過程。為了幫助你在PHP編程中更好地應(yīng)用和理解算法,今天我們要介紹一些很有用的PHP算法題庫。
1. CodeSignal
CodeSignal 是一個面向開發(fā)人員的技能評估平臺,它提供了大量的編程題目和挑戰(zhàn)。你可以在這個平臺上找到很多關(guān)于PHP算法的題目,并通過解答這些題目來提升自己的編程能力。CodeSignal 的題目涵蓋了各個難度級別,從入門到高級,適合不同水平的開發(fā)人員。此外,CodeSignal 還提供了社區(qū)功能,你可以與其他開發(fā)人員交流和分享解題思路。
2. LeetCode
LeetCode 是一個非常流行的在線編程平臺,它提供了大量的算法題目。你可以使用PHP解答這些題目,并在上面的討論區(qū)與其他開發(fā)人員交流和學(xué)習(xí)。LeetCode 的題庫非常全面,覆蓋了各種不同類型的算法問題,包括數(shù)組、字符串、鏈表、樹等等。解答這些問題可以幫助你更好地理解PHP的數(shù)據(jù)結(jié)構(gòu)和算法。
3. HackerRank
HackerRank 是一個技術(shù)面試和編程競賽平臺,它也提供了許多PHP算法題目。通過解答這些題目,你可以進(jìn)行技術(shù)練習(xí),并將自己的解答與其他開發(fā)人員進(jìn)行比較。HackerRank 的題庫涵蓋了各個難度級別,從入門到高級,適合不同水平的開發(fā)人員。
4. Project Euler
Project Euler 是一個以數(shù)學(xué)和計(jì)算為主題的編程挑戰(zhàn)平臺。盡管它的題目不是專門為PHP開發(fā)人員設(shè)計(jì)的,但通過解答這些題目,你可以提升你的編程技能,并且更好地理解算法的應(yīng)用。Project Euler 的題目涵蓋了各種數(shù)學(xué)問題,其中很多問題可以用PHP解決。
5. Codewars
Codewars 是一個以編程挑戰(zhàn)為主題的平臺,它提供了大量的算法題目。你可以選擇不同級別的挑戰(zhàn),并通過解答這些題目來提升自己的編程能力。Codewars 的題目包括了許多與PHP相關(guān)的問題,可以幫助你更好地理解PHP的特性和語法。
6. Topcoder
Topcoder 是一個專業(yè)的算法競賽平臺,它提供了各種不同類型的算法題目。雖然 Topcoder 的題目不是專門為PHP開發(fā)人員設(shè)計(jì)的,但通過解答這些題目,你可以提升你的算法思維和解決問題的能力。Topcoder 的題目難度很高,適合有一定編程經(jīng)驗(yàn)的開發(fā)人員。
以上是一些非常有用的PHP算法題庫,通過解答這些題目,你可以提升自己的編程技能和算法思維。不論你是初學(xué)者還是有經(jīng)驗(yàn)的開發(fā)人員,挑戰(zhàn)不同難度級別的題目都能幫助你不斷進(jìn)步。如果你想在PHP編程中更加高效和靈活地應(yīng)用算法,那么這些題庫將是你的良師益友。加油!
在計(jì)算機(jī)科學(xué)中,算法是解決問題的步驟和方法的描述,它是解決問題的有效工具。
對于那些使用PHP編程語言的開發(fā)人員來說,了解和應(yīng)用各種算法是提高代碼質(zhì)量和性能的關(guān)鍵。本文將介紹一些與PHP算法相關(guān)的書籍,幫助你深入理解算法并提升自己的編程技能。
《算法導(dǎo)論》是由Thomas H. Cormen等人編寫的經(jīng)典教材,它詳盡地介紹了各種常見的算法和數(shù)據(jù)結(jié)構(gòu)。這本書對于計(jì)算機(jī)科學(xué)專業(yè)的學(xué)生來說非常重要,無論是入門還是進(jìn)階,都能從中受益匪淺。
利用語言書寫代碼時,掌握一些高效的算法可以極大地提升網(wǎng)頁的性能。如何快速排序、查找最短路徑、優(yōu)化搜索算法等等,這些內(nèi)容都可以在《算法導(dǎo)論》中找到詳細(xì)解釋。不僅如此,書中的練習(xí)題和示例代碼也讓你有機(jī)會實(shí)際動手應(yīng)用這些算法。
對于初學(xué)者或?qū)λ惴ǜ械嚼Щ蟮拈_發(fā)人員來說,《算法圖解》是一個很好的起點(diǎn)。這本書以圖解的方式介紹了常見的算法和數(shù)據(jù)結(jié)構(gòu),用簡單明了的語言解釋復(fù)雜的概念。
PHP語言的特點(diǎn)是簡潔易懂,結(jié)合《算法圖解》一書,你可以更深入地理解和應(yīng)用各種算法。書中的示例代碼使用PHP語言編寫,方便實(shí)踐和理解算法的運(yùn)行過程。
《算法筆記》是國內(nèi)著名的算法教材,深受學(xué)生和開發(fā)人員的喜愛。它的特點(diǎn)是通俗易懂,注重算法的實(shí)際應(yīng)用。這本書以PHP語言為例,詳細(xì)講解了常用的算法設(shè)計(jì)思想和解題思路。
PHP算法的學(xué)習(xí)沒有固定的先后順序,因此《算法筆記》適合初學(xué)者和有一定編程基礎(chǔ)的人閱讀。書中的例子豐富多樣,通過實(shí)際案例分析,幫助讀者理解和掌握不同類型的算法。
如果你希望通過實(shí)踐來學(xué)習(xí)PHP算法與數(shù)據(jù)結(jié)構(gòu),那么《PHP算法與數(shù)據(jù)結(jié)構(gòu)實(shí)戰(zhàn)教程》是一個不錯的選擇。本書重點(diǎn)關(guān)注PHP語言中的常用算法和數(shù)據(jù)結(jié)構(gòu)的實(shí)際應(yīng)用。
在該書中,你將學(xué)習(xí)到如何使用PHP編寫二分搜索算法、堆排序算法、動態(tài)規(guī)劃算法等等。此外,書中還介紹了PHP中常用的數(shù)據(jù)結(jié)構(gòu),如鏈表、棧、隊(duì)列等,并通過實(shí)戰(zhàn)示例展示其在實(shí)際項(xiàng)目中的應(yīng)用。
雖然不是嚴(yán)格意義上的算法書籍,但《PHP設(shè)計(jì)模式與最佳實(shí)踐》對于PHP開發(fā)人員來說是一本非常有價值的書。設(shè)計(jì)模式是一種解決問題的方法,它能夠組織代碼,提高可讀性和可維護(hù)性。
在PHP編程中,合理使用設(shè)計(jì)模式可以使代碼更加優(yōu)雅且易于維護(hù)?!禤HP設(shè)計(jì)模式與最佳實(shí)踐》一書通過實(shí)例介紹了常用的設(shè)計(jì)模式,并結(jié)合實(shí)際項(xiàng)目示例說明了它們的應(yīng)用場景。
掌握設(shè)計(jì)模式有助于你在PHP編程中更好地組織代碼,提高代碼的可重用性和可擴(kuò)展性,進(jìn)而在實(shí)際應(yīng)用中實(shí)現(xiàn)高效的算法。
無論你是PHP初學(xué)者還是經(jīng)驗(yàn)豐富的開發(fā)人員,理解和應(yīng)用不同的算法都是提高自己的編程水平的關(guān)鍵。通過閱讀上述推薦的書籍,你將為自己打下堅(jiān)實(shí)的算法基礎(chǔ),更好地應(yīng)對PHP編程中遇到的各種挑戰(zhàn)。
按數(shù)量級遞增排列,常見的時間復(fù)雜度有:常數(shù)階O(1),對數(shù)階O(log2n),線性階O(n),線性對數(shù)階O(nlog2n),平方階O(n2),立方階O(n3)
復(fù)制代碼 代碼如下:
//二分查找O(log2n)
function erfen($a,$l,$h,$f){
if($l >$h){ return false;}
$m = intval(($l+$h)/2);
if ($a[$m] == $f){
return $m;
}elseif ($f < $a[$m]){
return erfen($a, $l, $m-1, $f);
}else{
return erfen($a, $m+1, $h, $f);
}
}
$a = array(1,12,23,67,88,100);
var_dump(erfen($a,0,5,1));
//遍歷樹O(log2n)
function bianli($p){
$a = array();
foreach (glob($p.'/*') as $f){
if(is_dir($f)){
$a = array_merge($a,bianli($f));
}else{
$a[] = $f;
}
}
return $a;
}
//階乘O(log2n)
function jc($n){
if($n<=1){
return 1;
}else{
return $n*jc($n-1);
}
}
//快速查找 O(n *log2(n))
function kuaisu($a){
$c = count($a);
if($c <= 1){return $a;}
$l = $r = array();
for ($i=1;$i<$c;$i++){
if($a[$i] < $a[0]){
$l[] = $a[$i];
}else{
$r[] = $a[$i];
}
}
$l = kuaisu($l);
$r = kuaisu($r);
return array_merge($l,array($a[0]),$r);
}
//插入排序 O(N*N)
function charu($a){
$c = count($a);
for($i=1;$i<$c;$i++){
$t = $a[$i];
for($j=$i;$j>0 && $a[$j-1]>$t;$j--){
$a[$j] = $a[$j-1];
}
$a[$j] = $t;
}
return $a;
}
//選擇排序O(N*N)
function xuanze($a){
$c = count($a);
for($i=0;$i<$c;$i++){
for ($j=$i+1;$j<$c;$j++){
if($a[$i]>$a[$j]){
$t = $a[$j];
$a[$j] = $a[$i];
$a[$i] = $t;
}
}
}
return $a;
}
//冒泡排序 O(N*N)
function maopao($a){
$c = count($a);
for($i=0;$i<$c;$i++){
for ($j=$c-1;$j>$i;$j--){
if($a[$j] < $a[$j-1]){
$t = $a[$j-1];
$a[$j-1] = $a[$j];
$a[$j] = $t;
}
}
}
return $a;
}
復(fù)制代碼 代碼如下:
/**
* 排列組合
* 采用二進(jìn)制方法進(jìn)行組合的選擇,如表示5選3時,只需有3位為1就可以了,所以可得到的組合是 01101 11100 00111 10011 01110等10種組合
*
* @param 需要排列的數(shù)組 $arr
* @param 最小個數(shù) $min_size
* @return 滿足條件的新數(shù)組組合
*/
function plzh($arr,$size=5) {
$len = count($arr);
$max = pow(2,$len);
$min = pow(2,$size)-1;
$r_arr = array();
for ($i=$min; $i<$max; $i++){
$count = 0;
$t_arr = array();
for ($j=0; $j<$len; $j++){
$a = pow(2, $j);
$t = $i&$a;
if($t == $a){
$t_arr[] = $arr[$j];
$count++;
}
}
if($count == $size){
$r_arr[] = $t_arr;
}
}
return $r_arr;
}
$pl = pl(array(1,2,3,4,5,6,7),5);
var_dump($pl);