題:從一個字符串中找到一個連續子串,該子串中任何兩個字符不能相同,求子串的最大長度並輸出一條最長不重複子串。算法
本身的第一反應是使用動態規劃來解決這個問題。在蒐集資料以後,發現共有三種解決方案:
spa
使用hashcode
使用DP + Hash索引
==================================================================
字符串
基本方法,使用簡單Hashstring
其實判斷重複問題最應該想到的是Hash,創建一個簡單的hash table,key爲字符的ASCII碼值,value爲該字符是否已經在當前子串中出現過(出現過爲1,未出現爲0)。最簡單的方法就是對全部的子串進行查重,複雜度爲θ(n^2)。hash
在掃描過程當中,咱們須要找到儘量長的不重複子串,我稱之爲「極長不重複子串」。假設s[i...j]的當前的極長不重複子串爲L(i,j),那麼L(i, j+1)的長度分爲兩種狀況:it
1. 上一個s[j+1]表明的字符出如今L(i.j)的起始位置以前,那麼s[j+1]應該被添加到當前極長不重複子串中;io
2. 上一個s[j+1]表明的字符出如今L(i,j)的起始位置以後,那麼記錄下L(i,j),開始跟蹤新的極長不重複子串。
table
在掃描完全部的str[0...n],str[1...n],str[2...n]....後,最長的極長字符串就是字長不重複子串
源代碼爲:
/* 最長不重複子串 設串不超過30 * 咱們記爲 LNRS */ int maxlen; int maxindex; void output(char * arr); /* LNRS 基本算法 hash */ char visit[256]; void LNRS_hash(char * arr, int size) { int i, j; for(i = 0; i < size; ++i) { memset(visit,0,sizeof visit); visit[arr[i]] = 1; for(j = i+1; j < size; ++j) { if(visit[arr[j]] == 0) { visit[arr[j]] = 1; }else { if(j-i > maxlen) { maxlen = j - i; maxindex = i; } break; } } if((j == size) && (j-i > maxlen)) { maxlen = j - i; maxindex = i; } } output(arr); }
=========================================================================
使用DP+hash。使用DP以空間換時間的方法來解決此問題,DP最重要的思想就是要記錄。
在第一種方法當中,咱們掃面了全部的子串。可是若是str1是str2的子串,那麼str1的最長不重複子串確定小於或者等於str2。咱們能夠直接掃描整個給定的字符串,並在掃描過程當中記錄下全部掃描到極大字符串,找到最長的便可(仿照人工的思路)。
使用hash表來保存一個字符最近被掃描的時候所處的位置
代碼以下:
class Solution { public: int lengthOfLongestSubstring(string s) { if (s.empty()) return 0; int visit[256]; //用來保存最近掃描到一個字符的位置 int max_length; //目前最大不重複子串的長度 int start_index; //目前最大不重複子串的起始索引 int last_start; //目前掃描的極大不重複子串的起始索引 int last_length; //目前掃描的極大不重複子串的長度 start_index = 0; max_length = 0; last_start = 0; memset(visit, -1, sizeof(int) * 256); //第一個字符 visit[s[0]] = 0; last_length = 1; for (int i = 1; i < s.size(); i++) { if (visit[s[i]] == -1) { last_length++; visit[s[i]] = i; } else if (visit[s[i]] < last_start) { last_length++; visit[s[i]] = i; } else { if (last_length > max_length) { max_length = last_length; start_index = last_start; last_start = visit[s[i]] + 1; //更新當前極長子串的起點,是重複字符的後一位 last_length = i - last_start + 1; visit[s[i]] = i; } else { last_start = visit[s[i]] + 1; last_length = i - last_start + 1; visit[s[i]] = i; } } } if (last_length > max_length) { max_length = last_length; } return max_length; } };