LeetCode刷题:字符串(Java|C++实现)

有关字符串类型的题目都会总结记录在此,方便自己日后查看。

1002.查找常用字符

给定仅有小写字母组成的字符串数组A,返回列表中的每个字符串中都显示的全部字符(包括重复字符)组成的列表。例如,如果一个字符在每个字符串中出现 3 次,但不是 4次,则需要在最终答案中包含该字符 3 次。你可以按任意顺序返回答案。

  • 个人解题思路:
    个人的一般思路(不得不说官方还是巧妙的很),用一个二维数组map[words][26](输入有多少个单词,就有多少行,每列对应a-z)存储每个单词各个字母的出现次数。之后遍历map,判断每列是否都不为0(有出现0说明此列对应的字母并非所有单词都包含,应当舍弃),是的话就取每列最小值,即重复次数,并保存对应字母到列表里。如下图所示:
    在这里插入图片描述
  • JAVA代码
import java.util.LinkedList;
import java.util.List;

public class 查找常用字符1002 {
	static class Solution {
	    public List<String> commonChars(String[] words) {
	    	List<String> list=new LinkedList<String>();
	    	int map[][]=new int[words.length][26];
	    	for (int i = 0; i < words.length; i++) {
	    		char c[]=words[i].toCharArray();
				for (int j = 0; j < c.length; j++) {
					map[i][c[j]-'a']+=1;
				}
			}
            //打印看看map保存的对不对
//	    	for (int i = 0; i < map[0].length; i++) {
//	    		System.out.print(""+(char)('a'+i)+" ");
//			}
//	    	System.out.println("");
//	    	for (int i = 0; i < map.length; i++) {
//				for (int j = 0; j < map[0].length; j++) {
//					System.out.print(map[i][j]+" ");
//				}
//				System.out.println(":"+words[i]);
//			}
	    	
	    	for (int i = 0; i < map[0].length; i++) {
	    		int min=Integer.MAX_VALUE;
	    		int j=0;
				for (j = 0; j < map.length; j++) {
					if (map[j][i]<min) {
						min=map[j][i];
						if (min==0) {
							break;
						}
					}
				}
				for (int k = 0; k < min; k++) {
					list.add(""+(char)('a'+i));				
				}
			}
	    	return list;
	    }
	}
	public static void main(String[] args) {
		String string[]= {"bella","label","roller"};
		Solution solution=new Solution();			
		List<String> list=solution.commonChars(string);
		for (int i = 0; i < list.size(); i++) {
			System.out.println(list.get(i));
		}
		
	}
}
  • C++
    不得不说,C++数组是真的麻烦
#include<iostream>
#include<vector>
#include<string>
using namespace std;
class Solution {
public:
	vector<string> commonChars(vector<string>& words) {
		vector<string> list;
		vector<vector<int>> map(words.size());
		for (int i = 0; i < map.size(); i++) {
			map[i].resize(26);	
		}

		for (int i = 0; i < words.size(); i++) {
			for (int j = 0; j < words[i].length(); j++) {
				map[i][words[i][j] - 'a'] += 1;
			}
		}

		for (int i = 0; i < map[0].size(); i++) {
			int min = INT_MAX;
			int j = 0;
			for (j = 0; j < map.size(); j++) {
				if (map[j][i] < min) {
					min = map[j][i];
					if (min == 0) {
						break;
					}
				}
			}
			for (int k = 0; k < min; k++) {
				//用emplace_back效率高,且参数不必是对象
				list.emplace_back(1, i+'a');
			}
		}
		return list;
    }
};
  • C++代码(官方)
class Solution {
public:
    vector<string> commonChars(vector<string>& words) {
        vector<int> minfreq(26, INT_MAX);
        vector<int> freq(26);
        for (const string& word : words) {
            fill(freq.begin(), freq.end(), 0);
            for (char ch : word) {
                ++freq[ch - 'a'];
            }
            for (int i = 0; i < 26; ++i) {
                minfreq[i] = min(minfreq[i], freq[i]);
            }
        }

        vector<string> ans;
        for (int i = 0; i < 26; ++i) {
            for (int j = 0; j < minfreq[i]; ++j) {
            //用emplace_back效率高,且参数不必是对象
                ans.emplace_back(1, i + 'a');
            }
        }
        return ans;
    }
};

5.最长回文子串

给你一个字符串 s,找到 s 中最长的回文子串

  • 个人解题思路
    第一时间还是想到暴力,采用双指针,从字符串第一个字母开始,以其为中心向两边扫,一旦发现不是回文串,则退出,然后以字符串第二个字母为中心,以此类推,直至扫完整个串,中途不断保存最长的串就可以了。主要需要注意的是回文串有两种类型,aba和baab,加个flag分情况就行了。
    发现这个暴力法也是可以AC的嘿嘿,虽然击败的人比较少。
    在这里插入图片描述

  • JAVA代码

public class 最长回文子串5 {
	static class Solution {
		static String getlongest(String s,int flag) {
			String string="";
	    	char c[]=s.toCharArray();
	    	for (int pos = 0; pos < c.length; pos++) {
	    		//用flag标志是aba型还是baab型。
	    		int left=pos,right=pos+flag;
	    		String roll="";
	    		while (true) {
	    			if(left<0||right>=c.length)break;
					if (c[left]==c[right]) {
						left-=1;
						right+=1;					
					}
					else break;
				}
	    		int begin=left+1;
	    		int end=right-1;
	    		for (int j = begin; j <= end; j++) {
					roll+=c[j];
				}
	    		if(roll.length()>string.length()) {
	    			string=roll;
	    		}
			}    	
	    	return string;
		}
	    public String longestPalindrome(String s) {
	    	String s1=getlongest(s, 0);
	    	String s2=getlongest(s, 1);
	    	return s1.length()>s2.length()?s1:s2;
	    }
	}
	public static void main(String[] args) {
		Solution s=new Solution();
		System.out.println(s.longestPalindrome("abbacd"));
	}
}

记录一下正解吧,动态规划方法。

  • 用 P(i,j)表示字符串 s 的第i到j个字母组成的串(即 S[i:j])是否为回文串。
  • 可以发现,若s[i:j]为回文串,则S[i+1:j-1]一定也为回文串,可以写出动态规划的状态转移方程:
    P(i,j)=P(i+1,j−1)∧(Si==Sj)
  • 边界条件:对于长度为 1 的子串,它显然是个回文串;对于长度为 2 的子串,只要它的两个字母相同,它就是一个回文串。
    P(i,i)=true,P(i,i+1)=(Si==Si+1)

JAVA和C++代码如下:

public class Solution {

    public String longestPalindrome(String s) {
        int len = s.length();
        if (len < 2) {
            return s;
        }

        int maxLen = 1;
        int begin = 0;
        // dp[i][j] 表示 s[i..j] 是否是回文串
        boolean[][] dp = new boolean[len][len];
        // 初始化:所有长度为 1 的子串都是回文串
        for (int i = 0; i < len; i++) {
            dp[i][i] = true;
        }

        char[] charArray = s.toCharArray();
        // 递推开始
        // 先枚举子串长度
        for (int L = 2; L <= len; L++) {
            // 枚举左边界,左边界的上限设置可以宽松一些
            for (int i = 0; i < len; i++) {
                // 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
                int j = L + i - 1;
                // 如果右边界越界,就可以退出当前循环
                if (j >= len) {
                    break;
                }

                if (charArray[i] != charArray[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i < 3) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substring(begin, begin + maxLen);
    }
}

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/
来源:力扣(LeetCode
#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        if (n < 2) {
            return s;
        }

        int maxLen = 1;
        int begin = 0;
        // dp[i][j] 表示 s[i..j] 是否是回文串
        vector<vector<int>> dp(n, vector<int>(n));
        // 初始化:所有长度为 1 的子串都是回文串
        for (int i = 0; i < n; i++) {
            dp[i][i] = true;
        }
        // 递推开始
        // 先枚举子串长度
        for (int L = 2; L <= n; L++) {
            // 枚举左边界,左边界的上限设置可以宽松一些
            for (int i = 0; i < n; i++) {
                // 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
                int j = L + i - 1;
                // 如果右边界越界,就可以退出当前循环
                if (j >= n) {
                    break;
                }

                if (s[i] != s[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i < 3) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substr(begin, maxLen);
    }
};

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/longest-palindromic-substring/solution/zui-chang-hui-wen-zi-chuan-by-leetcode-solution/
来源:力扣(LeetCode)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hilbob

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值