(LeetCode刷題)Day03 無重複字符的最長子串

鳴謝: LeetCode-In-Go

3. Longest Substring Without Repeating Characters

題目

Given a string, find the length of the longest substring without repeating characters.

Examples:

Given “abcabcbb”, the answer is “abc”, which the length is 3.

Given “bbbbb”, the answer is “b”, with the length of 1.

Given “pwwkew”, the answer is “wke”, with the length of 3. Note that the answer must be a substring, “pwke” is a subsequence and not a substring.

在這裏插入圖片描述
在這裏插入圖片描述

解題思路

利用s[left:i+1]來表示s[:i+1]中的包含s[i]的最長子字符串。
location[s[i]]是字符s[i]在s[:i+1]中倒數第二次出現的序列號。
當left < location[s[i]]的時候,說明字符s[i]出現了兩次。需要設置 left = location[s[i]] + 1,
保證字符s[i]只出現一次。

提交代碼

解法一、滑動窗口法

在這裏插入圖片描述
時間複雜度:O(n2)O(n^2)

空間複雜度:O(1)O(1)

C++代碼

class Solution
{
public:
    int lengthOfLongestSubstring(string s)
    {
        //s[start,end) 前面包含 後面不包含
        int start(0), end(0), length(0), result(0);
        int sSize = int(s.size());
        while (end < sSize)
        {
            char tmpChar = s[end];
            for (int index = start; index < end; index++)
            {
                if (tmpChar == s[index])
                {
                    start = index + 1;
                    length = end - start;
                    break;
                }
            }

            end++;
            length++;
            result = max(result, length);
        }
        return result;
    }
};

Golang代碼


// 解題思路
/*
利用s[left:i+1]來表示s[:i+1]中的包含s[i]的最長子字符串。
location[s[i]]是字符s[i]在s[:i+1]中倒數第二次出現的序列號。
當left < location[s[i]]的時候,說明字符s[i]出現了兩次。需要設置 left = location[s[i]] + 1,
保證字符s[i]只出現一次。
*/
func lengthOfLongestSubstring(s string) int {
	if len(s) == 0 {
		return 0
	}
    // location[s[i]] == j 表示:
    // s中第i個字符串,上次出現在s的j位置,所以,在s[j + 1:i]中沒有s[i]
    // location[s[i]] == -1: s[i] 在s中第一次出現
    location := [256]int{}  // 只有256長是因爲,假定輸入的字符串只有ASCII字符
    for i := range location {
        location[i] = -1    // 先設置所有字符都是沒有碰到過的
    }
    
    maxLen, left := 0,0
    
    for i := 0; i < len(s); i++ {
        // 說明s[i]已經在s[left:i+1]中重複了
        // 並且s[i]上次出現的位置在location[s[i]]
        if location[s[i]] >= left {
            left = location[s[i]] + 1   // 在在s[left:i+1]中去除s[i]字符及其之前的部分
        } else if i + 1 - left > maxLen {
            maxLen = i + 1 - left
        }
        location[s[i]] = i
    }
    
    return maxLen
}

範例題解 - 4ms

在這裏插入圖片描述

// 整體思想是一樣的,存放數據的位置的結構換成了map
func lengthOfLongestSubstring(s string) int {
	if len(s) == 0 {
		return 0
	}
    maxLength := 0
	start := 0
	charMap := make(map[rune]int)
	//go中的string底層是通過byte來實現的
	for i, ch := range []rune(s){
		if  lastPos, ok := charMap[ch];ok && lastPos >= start{
			start = lastPos + 1
		}

		if i - start + 1 > maxLength {
			maxLength = i - start + 1
		}
		charMap[ch] = i
	}
	return maxLength
}

範例題解 - 0ms

這個方法去掉了存儲位置的數據結構,直接在循環裏面進行數據的比較和判斷。

func lengthOfLongestSubstring(s string) int {
	if len(s) == 0 {
		return 0
	}
	var sln int
	for t, e, c, d := 0, -1, 0, 0; c < len(s); c++ {
		for d = t; d <= e; d++ {
			if s[d] == s[c] {
				break
			}
		}
		if d > e { // new char
			e = c
			if e-t+1 > sln {
				sln = e - t + 1
			}
		} else { // existed
			t = d + 1
			e = c
		}
	}
	return sln
}

小結

利用Location保存字符上次出現的序列號,避免了查詢工作。location和Two Sum中的m是一樣的作用。

    // m 負責保存map[整數]整數的序列號
    m := make(map[int]int, len(nums))

編寫本地測試

package problem0003

import (
	"testing"

	"github.com/stretchr/testify/assert"
)

type para struct {
	one string
}

type ans struct {
	one int
}

type question struct {
	p para
	a ans
}

func Test_OK(t *testing.T) {
	ast := assert.New(t)

	qs := []question{
		question{
			p: para{
				one: "abcabcbb",
			},
			a: ans{
				one: 3,
			},
		},
		question{
			p: para{
				one: "bbbbbbbb",
			},
			a: ans{
				one: 1,
			},
		},
		question{
			p: para{
				one: "pwwkew",
			},
			a: ans{
				one: 3,
			},
		},
	}

	for _, q := range qs {
		a, p := q.a, q.p
		ast.Equal(a.one, lengthOfLongestSubstring(p.one), "輸入:%v", p)
	}
}

解法二、利用HashMap優化

在這裏插入圖片描述
時間複雜度:O(n)O(n)

空間複雜度:O(n)O(n)

C++代碼

class Solution
{
public:
    int lengthOfLongestSubstring(string s)
    {
        //s[start,end) 前面包含 後面不包含
        int start(0), end(0), length(0), result(0);
        int sSize = int(s.size());
        unordered_map<char, int> hash;
        while (end < sSize)
        {
            char tmpChar = s[end];
            //僅當s[start,end) 中存在s[end]時更新start
            if (hash.find(tmpChar) != hash.end() && hash[tmpChar] >= start)
            {
                start = hash[tmpChar] + 1;
                length = end - start;
            }
            hash[tmpChar] = end;

            end++;
            length++;
            result = max(result, length);
        }
        return result;
    }
};

作者:pinku-2
鏈接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-cshi-xian-/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

Golang代碼

func lengthOfLongestSubstring(s string ) int {

	var i, j int
	i = 0
	max := 0
	m := []byte(s)
	n := make(map[byte]int)


	for j = 0; j <len(s); j++ {

		l, ok := n[m[j]]
		if ok {
			delMap(l,i,m,n)
			i=l+1
			n[m[j]] = j
		} else {
			n[m[j]] = j

			if j-i+1 > max {
				max = j-i+1

			}
		}
	}
	return max
}


func delMap(l int,i int,m []byte,n map[byte]int){
	if l>i{
		for{
			delete(n,m[i])
			i++
			if i>l{
				break
			}
		}
	}else{
		delete(n,m[l])
	}
}

解法三、利用數組代替hashmap

在這裏插入圖片描述
時間複雜度: O(n)O(n)

控件複雜度: O(n)O(n)

C++代碼

class Solution
{
public:
    int lengthOfLongestSubstring(string s)
    {
        //s[start,end) 前面包含 後面不包含
        int start(0), end(0), length(0), result(0);
        int sSize = int(s.size());
        vector<int> vec(128, -1);
        while (end < sSize)
        {
            char tmpChar = s[end];
            //僅當s[start,end) 中存在s[end]時更新start
            if (vec[int(tmpChar)] >= start)
            {
                start = vec[int(tmpChar)] + 1;
                length = end - start;
            }
            vec[int(tmpChar)] = end;

            end++;
            length++;
            result = max(result, length);
        }
        return result;
    }
};

作者:pinku-2
鏈接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/solution/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-cshi-xian-/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

Golang代碼

func lengthOfLongestSubstring(s string) int {
	slen := len(s)
	if slen == 0 {
		return 0
	}

	dp := make([]int, 256)
	str := []byte(s)

	maxNum := 1
	l := 0
	h := 0
	var flag bool
	var sameChar byte

	for l <= h && h < slen {
		if flag {
			dp[str[l]]--
			if str[l] ==  sameChar && dp[str[l]] == 1 {
				flag = false
				sameChar = 0
			}
			l++
			continue
		}

		if dp[str[h]] == 0 {
			dp[str[h]] = 1
			if h-l+1 > maxNum {
				maxNum = h-l+1
			}
		}else {
			dp[str[h]]++
			flag = true
			sameChar = str[h]
		}
		h++
	}

	return maxNum

}

在這裏插入圖片描述
成長,就是一個不動聲色的過程,一個人熬過一些苦,才能無所不能。 ​​​​

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章