引言
今天想寫的太多了,廢話的開場白不說了。
(1)字符串的輸入 gets 和 scanf() 的區別需要注意
(2)兩種方法吧
第一種運行復雜數據會超時的暴力方法,最起碼可以解決問題,看着讓自己還不算是那麼沒用,思路也算清晰
第二種是滑動窗口算法,看了網上好多大神的教學視頻,怎奈天資愚鈍,百思不得其解。多虧看了看視頻(侵刪)
題目描述
3.無重複字符的最長字串
給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。
示例 1:
輸入: "abcabcbb"
輸出: 3
解釋: 因爲無重複字符的最長子串是 "abc",所以其長度爲 3。
示例 2:
輸入: "bbbbb"
輸出: 1
解釋: 因爲無重複字符的最長子串是 "b",所以其長度爲 1。
示例 3:
輸入: "pwwkew"
輸出: 3
解釋: 因爲無重複字符的最長子串是 "wke",所以其長度爲 3。
請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
白話題目:
一串字符串,找出最長的子串(必須連着的,不是字序列)
算法:
字符指針表示字符串首地址,傳進來都得獲得長度
暴力解法:
(1)長度1,就返回一唄
(2)從i=0頭開始,循環往下找到每一個子串,看看這段長度裏面是否有重複的
(3)字符串查重方法,借用了一個128位的字符數組存ASCII碼
滑動窗口算法:
1. 需要輸出或比較的結果在原數據結構中是連續排列的(字符串中的連續不重複子串,數組中的連續元素最大和)
2. 每次窗口滑動時,只需觀察窗口兩端元素的變化,無論窗口多長,每次只操作兩個頭尾元素,當用到的窗口比較長時,可以顯著減少操作次數
3.L,R指定滑動窗口,R不停的擴大,即將進來的元素是否滿足無重複最長子串的條件,不滿足的話需要挪動L,之後再挪動R,知道R走完。
打字說明有些捉急,感興趣的可以參閱代碼註釋部分或者網上搜索愛學習的小鵬友的視頻講解,希望能有些意思。
視頻詳解地址:B站 愛學習的小鵬友【學渣帶你刷Leetcode】https://www.bilibili.com/video/BV1C7411y7gB?p=3
C語言完成代碼
略長,考慮以後往github上放一放吧。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXSIZE 1000
/*
超時示例
ASCII碼字符可以使用一個字節來表示,
有效取值範圍爲0~127,總共128個字符。
解題思路爲:
定義一個128字節大小char型數組,數組初始化爲0。
*/
int allUnique(char *s, int i,int j)
{
char flag[128];
int ret = 0;
memset(flag, 0, sizeof(flag)); //複製爲0;
for(; i<=j; i++)
{
if (flag[*(s+i)])
{
ret = 1; //有重複
break;
}
else
{
flag[*(s+i)] = 1;
}
}
return ret;
}
//最笨方法沒有之一
int lengthOfLongestSubstring1(char * s)
{
int length=0;
int n=strlen(s); //原始有多長
//printf("%d\n",n);
int i,j;
//遍歷所有的子字符串,記錄沒有重複字母的子字符串的最大的長度
//獲取子字符串時,使用兩個標籤,分別代表子字符串的開頭和結尾
if(n==1)
{
length=1;
return length;
}
for(i=0; i<n; i++)
{
length=(length>(1)?length:(1));
for(j=i+1; j<n; j++)
{
//當子字符串沒有重複字母時,ans記錄最大的長度
if(!allUnique(s,i,j))
{
length=(length>(j-i+1)?length:(j-i+1));
// printf("%d %d---------- %d\n",i,j,length);
}
}
}
return length;
}
/*1. 需要輸出或比較的結果在原數據結構中是連續排列的(字符串中的連續不重複子串,數組中的連續元素最大和)
2. 每次窗口滑動時,只需觀察窗口兩端元素的變化,無論窗口多長,每次只操作兩個頭尾元素,當用到的窗口比較長時,可以顯著減少操作次數
*/
int lengthOfLongestSubstring2(char * s)
{
int L = 0, R = 0,k;
int maxlen = 0;
int curlen = 0;
int n = strlen(s);
if (n == 0)
return 0;
// for (; R < n &&(maxlen+L)<n; R++) //這個一開始想不到也很正常吧?算是優化?L+現在最大的都大於n了還用你算啥啊
for (; R < n ; R++) //別光想着小姐姐僱傭僱傭的,目標是啥,是得循環完吧,
{
curlen++; //右移一下,長度就+1,一開始就由一個長度了,求最長的,那總得看看啥是常吧,就把L--R之間算是長度吧
for ( k = L; k <= R; k++) //從左邊開始比較,這裏面有沒有和要進來的相等的
{
// printf("%d %d\n",L,R);
if (s[k] == s[R + 1]) //腦袋往不往前伸,不等的時候腦袋就往前走,R++;每加完就得看看腿動不動
{
// printf("%c\n",s[R+1]);
if (curlen > maxlen) //看看當前快要動彈的位置是否大於最大長度唄
{
maxlen = curlen;
}
L = k + 1; //腿往前一移動
curlen = R - L + 1;//就把L--R之間算是長度吧
break; //這個for就算完成了,腦袋正常往前把S[R+1]帶進來就行了。
}
}
}
//這地方也別費勁想了,就是這些當前的長度和定義的最大長度,誰最長輸出誰吧
if (curlen > maxlen)
return curlen;
else
return maxlen;
}
int main()
{
//char s1[MAXSIZE];
//scanf("%s\n",s1); //scanf遇到空格會斷開!!!,這個位置不要加\n,畫蛇添足
//printf("%s %c\n",s1,s1[2]); //
//char st[3];
//printf("input string:\n");
//scanf("%s",st);
//printf("輸出測試%s\n",st);
printf("可以輸入的測試數據 abcabcbb bbbbbb pwwkew");
char *s;
s=(char *)malloc(sizeof(char));
//scanf("%s",s); //處理不了空格
gets(s);
printf("%s\n",s);
printf("最容易理解的直白做法:%d\n",lengthOfLongestSubstring1(s));//pointer,p
printf("滑動窗口(小姐姐):%d:\n",lengthOfLongestSubstring2(s));//pointer,p
return 0;
}