NULL
指針 - 無重複字符的最長子串
NULL
指針 - 無重複字符的最長子串1. NULL
指針
標準定義了 NULL
指針,它作爲一個特殊的指針變量,表示不指向任何東西。要使一個指針變量爲 NULL
,你可以給它賦一個零值。爲了測試一個指針變量是否爲 NULL
,你可以將它與零值進行比較。之所以選擇零這個值是因爲一種源代碼約定。就機器內部而言,NULL
指針的實際值可能與此不同。在這種情況下,編譯器將負責零值和內部值之間的翻譯轉換。
NULL
指針的概念是非常有用的,因爲它給了你一種方法,表示某個特定的指針目前並未指向任何東西。例如,一個用於在某個數組中查找某個特定值的函數可能返回一個指向查找到的數組元素的指針。如果該數組不包含指定條件的值,函數就返回一個 NULL
指針。這個技巧允許返回值傳達兩個不同片段的信息。首先,有沒有找到元素?其次,如果找到,它是哪個元素?
儘管這個技巧在 C 程序中極爲常用,但它違背了軟件工程的原則。用一個單一的值表示兩種不同的意思是件危險的事,因爲將來很容易無法弄清哪個纔是它真正的用意。在大型的程序中,這個問題更爲嚴重,因爲你不可能在頭腦中對整個設計一覽無餘。一種更爲安全的策略是讓函數返回兩個獨立的值:首先是個狀態值,用於提示查找是否成功;其次是個指針,當狀態值提示查找成功時,它所指向的就是查找到的元素。
對指針進行解引用操作可以獲得它所指向的值。但從定義上看,NULL
指針並未指向任何東西。因此,對一個 NULL
指針進行解引用操作是非法的。在對指針進行解引用操作之前,你首先必須確保它並非 NULL
指針。
如果對一個 NULL
指針進行間接訪問會發生什麼情況呢?它的結果因編譯器而異。在有些機器上,它會訪問內存位置零。編譯器能夠確保內存位置零沒有存儲任何變量,但機器並未妨礙你訪問或修改這個位置。這種行爲是非常不幸的,因爲程序包含了一個錯誤,但機器卻隱匿了它的症狀,這樣就使這個錯誤史加難以尋找。
在其他機器上,對 NULL
指針進行間接訪問將引發一個錯誤,並終止程序。宣佈這個錯誤比隱藏這個錯誤要好得多,因爲程序員能夠更容易修正它。
如果所有的指針變量 (而不僅僅是位於靜態內存中的指針變量) 能夠被自動初始化爲 NULL
,那實在是件幸事,但事實並非如此。不論你的機器對解引用 NULL
指針這種行爲作何反應,對所有的指針變量進行顯式的初始化是種好做法。如果你已經知道指針將被初始化爲什麼地址,就把它初始化爲該地址,否則就把它初始化爲 NULL
。風格良好的程序會在指針解引用之前對它進行檢查,這種初始化策略可以節省大量的調試時間。
2. 無重複字符的最長子串
給定一個字符串,請你找出其中不含有重複字符的最長子串的長度。
示例 1:
輸入:"abcabcbb"
輸出:3
解釋:因爲無重複字符的最長子串是 "abc",所以其長度爲 3。
示例 2:
輸入:"bbbbb"
輸出:1
解釋:因爲無重複字符的最長子串是 "b",所以其長度爲 1。
示例 3:
輸入:"pwwkew"
輸出:3
解釋:因爲無重複字符的最長子串是 "wke",所以其長度爲 3。你的答案必須是<font color=blue>**子串**</font>的長度,"pwke" 是一個子序列,不是子串。
2.1 滑動窗口 + 直方圖 (Histogram)
字符串 s
。
從左側開始遍歷 s
,以 i
標記窗口左側,j
標記窗口右側,初始時 i=0, j=0
,即開頭 a
所在的位置,窗口大小爲 1。然後將 j
右移,逐步擴大窗口,依次經過 b, c, d
,窗口內均無重複字符,繼續右移 j
。
當 j
移動到 d
後面的 a
所在位置時,對應字符 a
在窗口中已存在,此時,窗口大小爲 5,去除當前重複的一位,窗口大小爲 4。此時窗口內的字符串 abcd
爲
找到窗口中已存在的該字符所在位置,並將 i
移動到該位置下一位置。
此時爲第二個窗口。
繼續重複之前的操作,直到 j
移動到字符串最後一位停止。
int lengthOfLongestSubstring(char * s)
{
int len_s = 0;
char *ps = s;
int histogram_table[128] = { 0 };
int right_idx = 0, left_idx = 0;
int len_subs = 0, len_tmp = 0;
if (NULL == s)
{
return 0;
}
len_s = strlen(s);
// empty string
if (0 == len_s)
{
return 0;
}
right_idx = 0;
left_idx = 0;
for (right_idx = 0; right_idx < len_s; right_idx++)
{
if (0 != histogram_table[ps[right_idx]])
{
if (histogram_table[ps[right_idx]] - 1 >= left_idx)
{
left_idx = histogram_table[ps[right_idx]] - 1 + 1;
}
}
len_tmp = right_idx - left_idx + 1;
if (len_tmp > len_subs)
{
len_subs = len_tmp;
}
histogram_table[ps[right_idx]] = right_idx + 1;
}
return len_subs;
}