leetcode 字符串,子串,子序列,路径和相关问题

leetcode 5 最长回文子串

  • 2023.1.16 优化中心扩散的写法
var start,Len int
func longestPalindrome(s string) string {
    //中心扩散记录 start和Len ,而且分为 两种情况,当前点左右扩散和当前和右边的点共同扩散
    start = 0
    Len = 0
    for i:=0;i<len(s);i++{
        getLenght(s,i,i+1)
        getLenght(s,i,i)
    }
    return s[start:start+Len]
}

//计算长度
func getLenght(s string,l,r int){
    for l>=0&&r<len(s)&&s[l]==s[r]{
        l--
        r++
    }
    if r-l-1>Len{
        Len = r-l-1
        start = l+1
    }
}
  • 暴力解法,每个字母向两边扩散计算,复杂度O(n^2)
func longestPalindrome(s string) string {
    //两个for循环
    res:=""
    if len(s)==0{
        return res
    }
    //没有则返回第一个
    start,Len:=0,1
    for i:=0;i<len(s);i++{
        l,r:=i,i
        for l>=0&&r<len(s)&&s[l]==s[r]{
            l--
            r++
        }
        if r-l+1-2>Len{
            start = l+1
            Len = r-l-1
        }

        l,r = i,i+1
         for l>=0&&r<len(s)&&s[l]==s[r]{
            l--
            r++
        }
        if r-l+1-2>Len{
            start = l+1
            Len = r-l-1
        }
    }
    tmp:=[]byte(s)
    return string(tmp[start:start+Len])
}

func longestPalindrome(s string) string {
    //特殊判断
    if len(s)<1{
        return s
    }
    res:=s
    start,Len:=0,0
    size:=2*len(s)+1
    //右侧最远和对应的中心
    maxRight,center:=0,0
    //获取处理之后的字符串
    s=getstr(s)
    //p记录对应的长度
    p:=make([]int,size)
    
    for i:=0;i<size;i++{
        mirror:=2*center-i
        if p[i]<maxRight-i{ //复用前面计算过的
            p[i] = min(p[mirror],maxRight-i)
        }
        
        left,right:=i-(p[i]+1),i+(p[i]+1)
        for left>=0&&right<size&&s[left]==s[right]{
            p[i]++
            left--
            right++
        }

        //更新center和maxRight
        if i+p[i]>maxRight{
            maxRight = i+p[i]
            center = i 
        }

        //更新距离
        if p[i]>Len{
            Len = p[i]
            start = (i-Len)/2
        }

    }
  //从原来字符串截取
  tmp:=[]byte(res)
  return string(tmp[start:start+Len])
}

//增加间隔字符串
func getstr(str string)string{
     res:=[]byte{'#'}
     for i:=0;i<len(str);i++{
         res = append(res,str[i])
         res = append(res,'#')
     }
     return string(res)
     
}

func min(x,y int)int{
    if x>y{
        return y
    }else{
        return x
    }
}

leetcode387 字符串中第一个唯一字符

计数数组记录26个字母的数量

func firstUniqChar(s string) int {
	//记数数组
	flag:=make([]int,26)
	str:=[]rune(s)
	for i:=0;i<len(str);i++{
		flag[s[i]-'a']++
	}

	//找到第一个出现一次字符的位置
	for i:=0;i<len(str);i++{
		if flag[s[i]-'a']==1{
			return i
		}
	}
	return -1
}

8 实现atoi

注意可能出现的边界情况 -+123 纯空串“ ”

func myAtoi(s string) int {
	max:=math.MaxInt32
	min:=math.MinInt32
	str:=[]rune(s)
	//空返回0
	if len(str)==0{
		return 0
	}
	res:=0
	flag:=true
	i:=0
	for ;i<len(str);i++{
		if str[i]==' '{
			continue
		}else{
			break
		}
	}
	//前面全为空格
	if i>=len(str) {
		return 0
	}
	//判断正负号 可能出现-+情况
	if str[i]=='-'{
		flag = false
		i++
	}else if str[i]=='+'{
		i++
	}
	for ;i<len(str);i++{
		if str[i]>='0'&&str[i]<='9'{
			if flag{
				res = res*10+int(str[i]-'0')
				if res>max{
					res = max
					break
				}
			}else{
				res = res*10-int(str[i]-'0')
				if res<min{
					res = min
					break
				}
			}
		}else{
			break
		}
	}
	return res
}

451根据字符串出现频率进行排序

桶排序
c++ O(n) O(a)//a为出现次数最多的字符数

 string frequencySort(string s) {
        if(s.size()==0)return "";
        //桶排序  
        unordered_map<char,int>hash;
        int Maxlen = 0;
        //放字符 保留最大值
        for(int i=0;i<s.size();i++)
        {
            hash[s[i]]++;
            Maxlen = max(Maxlen,hash[s[i]]);
        }
        //放ascill值 容量为出现最多次数+1而不是hash.size()
        vector<vector<int>>buckets(Maxlen+1);
        for(unordered_map<char,int>::iterator iter=hash.begin();iter!=hash.end();iter++)
        {
            buckets[iter->second].push_back(iter->first);//上面使用最大次数的原因,不用会溢出
        }
        //输出字符串
        string res;
        for(int i=Maxlen;i>=1;i--)
        {
            for(int j=0;j<buckets[i].size();j++)
            {
                //放置多次
                for(int z = 0;z<i;z++)
                {
                    res.push_back(buckets[i][j]);
                }
            }
        }
        return res;
    }

1143. 最长公共子序列 (求具体序列)

  • 简单dp,注意求具体序列时,是逆序,每行判断是否dp[i][j]==length并且比上面和左边dp值大
func longestCommonSubsequence(text1 string, text2 string) int {
	//类似编辑距离 dp[i][j] 代表长度为i,j的最大编辑距离
	if len(text1)==0||len(text2)==0{
		return 0
	}

	m:=len(text1)
	n:=len(text2)
	dp:=make([][]int,m+1)
	for i:=0;i<=m;i++{
		dp[i] = make([]int,n+1)
	}

	for i:=1;i<=m;i++{
		for j:=1;j<=n;j++{
			if text1[i-1]==text2[j-1]{ //第i-1个 第j-1个最大子序列+1
				dp[i][j] = dp[i-1][j-1]+1
			}else{
				dp[i][j] = max(dp[i-1][j],dp[i][j-1])
			}
		}
	}

	//计算具体序列
	length:=dp[m][n]
	res:=[]byte{}
	for i:=m;i>0;i--{
		for j:=n;j>0;j--{
			if dp[i][j]==length&&dp[i][j]>dp[i-1][j]&&dp[i][j]>dp[i][j-1]{
				res = append([]byte{text1[i-1]},res...)  //先出现的放在后面
				length--
				break
			}
		}
	}
	fmt.Println(string(res))

	return dp[m][n]
}
  • 2022.5.23
func longestCommonSubsequence(text1 string, text2 string) int {
	//类似编辑距离 dp[i][j] 代表长度为i,j的最大编辑距离
	if len(text1)==0||len(text2)==0{
		return 0
	}

	m:=len(text1)
	n:=len(text2)
	dp:=make([][]int,m+1)
	for i:=0;i<=m;i++{
		dp[i] = make([]int,n+1)
	}

	for i:=1;i<=m;i++{
		for j:=1;j<=n;j++{
			if text1[i-1]==text2[j-1]{ //第i-1个 第j-1个最大子序列+1
				dp[i][j] = dp[i-1][j-1]+1
			}else{
				dp[i][j] = max(dp[i-1][j],dp[i][j-1])
			}
		}
	}

	//计算具体序列
	length:=dp[m][n]
	res:=[]byte{}
	for i:=m;i>0;i--{
		for j:=n;j>0;j--{
			if dp[i][j]==length&&dp[i][j]>dp[i-1][j]&&dp[i][j]>dp[i][j-1]{
				res = append([]byte{text1[i-1]},res...)  //先出现的放在后面
				length--
				break
			}
		}
	}
	fmt.Println(string(res))

	return dp[m][n]
}
64 最小路径和(求具体路径)
func minPathSum(grid [][]int) int {
	//简单dp 扩展为求具体路径
	m:=len(grid)
	n:=len(grid[0])
	dp:=make([][]int,m)
	for i:=0;i<m;i++{
		dp[i] = make([]int,n)
	}
	dp[0][0] = grid[0][0]
	for i:=1;i<m;i++{ //初始化边缘
		dp[i][0] = dp[i-1][0]+grid[i][0]
	}
	for i:=1;i<n;i++{
		dp[0][i] = dp[0][i-1]+grid[0][i]
	}

	for i:=1;i<m;i++{
		for j:=1;j<n;j++{
			dp[i][j] = min(dp[i-1][j],dp[i][j-1])+grid[i][j]
		}
	}

	//求具体路径,倒序推理
	list:=make([]int,0)
	i,j:=m-1,n-1
	list = append(list,grid[i][j])
	sum:=dp[m-1][n-1]
	for i>0||j>0{
		sum-=grid[i][j]
		if j-1>=0&&dp[i][j-1]==sum{ //一直到0的位置
			list = append(list,grid[i][j-1]) //list = append(list,[]int{i,j-1}) 更换为坐标
			j--
		}else{
			list = append(list,grid[i-1][j])
			i--
		}
	}
	fmt.Print(list)  //最后得到的是逆序的路径,reverse后即可得到正序

	return dp[m-1][n-1]
}
posted @ 2021-02-04 15:39  海拉尔  阅读(67)  评论(0编辑  收藏  举报