目录
1.验证回文串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[]
的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
示例 1:
输入:["h","e","l","l","o"] 输出:["o","l","l","e","h"]
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
head = 0
rear = len(s) - 1
while head < rear:
s[head], s[rear] = s[rear], s[head]
head += 1
rear -= 1
2.分割回文串
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。返回 s 所有可能的分割方案。
输入: "aab" 输出: [ ["aa","b"], ["a","a","b"] ]
class Solution:
def partition(self, s):
"""
:type s: str
:rtype: List[List[str]]
"""
if len(s) == 0:
return []
else:
res = []
self.partition_helper(s, [], res)
return res
def partition_helper(self, s, cur_res, result):
if len(s) == 0:
result.append(cur_res)
for i in range(1, len(s)+1):
if self.check(s[:i]):
self.partition_helper(s[i:], cur_res + [s[:i]], result)
def check(self, s):
if len(s) == 0:
return False
else:
start = 0
end = len(s) - 1
while start <= end:
if s[start] != s[end]:
return False
else:
start += 1
end -= 1
return True
3.单词拆分
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
示例 1:
输入: s = "leetcode", wordDict = ["leet", "code"] 输出: true 解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。示例 2:
输入: s = "applepenapple", wordDict = ["apple", "pen"] 输出: true 解释: 返回 true 因为"
applepenapple"
可以被拆分成"
apple pen apple" 注意你可以重复使用字典中的单词。
示例 3:
输入: s = "catsandog", wordDict = ["cats", "dog", "sand", "and", "cat"] 输出: false
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
#将list变为set
wordset = set(wordDict)
dp = [0 for _ in range(len(s))]
for i in range(len(s)):
for j in range(0,i+1):
if s[0:i+1] in wordset or s[j+1:i+1] in wordset and dp[j] ==1:
dp[i] = 1
break
return dp[len(s)-1] == 1
4.单词拆分II
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,在字符串中增加空格来构建一个句子,使得句子中所有的单词都在词典中。返回所有这些可能的句子。
说明:
分隔时可以重复使用字典中的单词。你可以假设字典中没有重复的单词。
输入: s = "catsanddog
" wordDict =["cat", "cats", "and", "sand", "dog"]
输出:[ "cats and dog", "cat sand dog" ]
示例 2:
输入: s = "pineapplepenapple" wordDict = ["apple", "pen", "applepen", "pine", "pineapple"] 输出: [ "pine apple pen apple", "pineapple pen apple", "pine applepen apple" ] 解释: 注意你可以重复使用字典中的单词。示例 3:
输入: s = "catsandog" wordDict = ["cats", "dog", "sand", "and", "cat"] 输出: []
class Solution(object):
def wordBreak(self, s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: List[str]
"""
res = []
if len(s) == 0 or not wordDict:
return []
strides = [len(x) for x in wordDict]
max_stride = max(strides)
stride_set = set(strides)
if self.canBreak(s, wordDict):
self.sub_wordBreak(s, wordDict, max_stride, stride_set, [], res)
return res
def sub_wordBreak(self, sub_s, wordDict, max_stride, stride, cur_result, result):
if len(sub_s) == 0:
result.append(" ".join(cur_result))
else:
for stride_length in stride:
if stride_length <= len(sub_s):
if sub_s[:stride_length] in wordDict:
self.sub_wordBreak(sub_s[stride_length:], wordDict, max_stride,stride, cur_result + [sub_s[:stride_length]], result)
def canBreak(self, s, wordDict):
can_make = [False] * (len(s)+1)
can_make[0] = True
for i in range(1, len(s)+1):
for j in range(i-1, -1, -1):
if can_make[j] and s[j:i] in wordDict:
can_make[i] = True
break
return can_make[-1]
5.实现Trie(前缀树)
实现一个 Trie (前缀树),包含 insert
, search
, 和 startsWith
这三个操作。
Trie trie = new Trie(); trie.insert("apple"); trie.search("apple"); // 返回 true trie.search("app"); // 返回 false trie.startsWith("app"); // 返回 true trie.insert("app"); trie.search("app"); // 返回 true说明:
- 你可以假设所有的输入都是由小写字母
a-z
构成的。- 保证所有输入均为非空字符串。
class Trie(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.dic = {}
self.prefix = set()
def insert(self, word):
"""
Inserts a word into the trie.
:type word: str
:rtype: void
"""
self.dic[word] = word
i = 1
while i < len(word)+1:
self.prefix.add(word[:i])
i += 1
def search(self, word):
"""
Returns if the word is in the trie.
:type word: str
:rtype: bool
"""
return True if word in self.dic else False
def startsWith(self, prefix):
"""
Returns if there is any word in the trie that starts with the given prefix.
:type prefix: str
:rtype: bool
"""
return True if prefix in self.prefix else False
6.单词搜索II
给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。
输入: words =["oath","pea","eat","rain"]
and board = [ ['o','a','a','n'], ['e','t','a','e'], ['i','h','k','r'], ['i','f','l','v'] ] 输出:["eat","oath"]
说明:
你可以假设所有输入都由小写字母a-z
组成。提示:
- 你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
- 如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。
class Solution {
private TrieNode root = new TrieNode();
private int[] row = new int[]{-1,1,0,0};
private int[] col = new int[]{0,0,-1,1};
public List<String> findWords(char[][] board, String[] words) {
//直接用 list 存,会出现 重复记录word 的情况。。。汗颜!
//List<String> results = new ArrayList<String>();
//改用 HashSet 暂存结果,确保不会出现重复word
HashSet<String> temp = new HashSet<>();
//前缀树
for(int i=0;i<words.length;i++){
TrieNode node = root;
for(int j=0;j<words[i].length();j++)
node = node.add(words[i].charAt(j));
node.word = words[i];
}
//DFS
boolean[][] visited = new boolean[board.length][board[0].length];
for(int i=0;i<board.length;i++){
for(int j=0;j<board[0].length;j++){
if(root.ifExists(board[i][j])){
find(board,visited,i,j,root,temp);
}
}
}
List<String> results = new ArrayList<String>();
results.addAll(temp);
return results;
}
private void find(char[][] board,boolean[][] visited,int x,int y,TrieNode node,HashSet<String> temp){
visited[x][y]=true;
TrieNode cur = node.next[board[x][y]-'a'];
//到达可匹配子串,记录当前 word
if(cur.word!=null)
temp.add(cur.word);
for(int i=0;i<4;i++){
int x2 = x + row[i];
int y2 = y + col[i];
if(x2>=0 && x2<board.length && y2 >=0 && y2 < board[0].length && !visited[x2][y2] ){
if(cur.ifExists(board[x2][y2])){
find(board,visited,x2,y2,cur,temp);
}
}
}
visited[x][y] = false;
}
//前缀树
class TrieNode{
String word;
TrieNode[] next = new TrieNode[26];
TrieNode add(char chr){
if(next[chr-'a'] != null)
return next[chr-'a'];
next[chr-'a'] = new TrieNode();
return next[chr-'a'];
}
boolean ifExists(char chr){
return (next[chr - 'a']==null)?false:true;
}
}
}
7.有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram" 输出: true说明:
你可以假设字符串只包含小写字母。进阶:
如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
class Solution(object):
def isAnagram(self, s, t):
"""
:type s: str
:type t: str
:rtype: bool
"""
return sorted(s)==sorted(t)
8.字符串中的第一个唯一字符
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
案例:
s = "leetcode" 返回 0. s = "loveleetcode", 返回 2.注意事项:您可以假定该字符串只包含小写字母。
class Solution(object):
def firstUniqChar(self, s):
"""
:type s: str
:rtype: int
"""
dic=collections.Counter(s)#使用字典
for i in range(len(s)):
if dic[s[i]]==1:#如果字典中value为1
return i
return -1
9.反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[]
的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符
示例 1:输入:["h","e","l","l","o"] 输出:["o","l","l","e","h"]
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
head = 0
rear = len(s) - 1
while head < rear:
s[head], s[rear] = s[rear], s[head]
head += 1
rear -= 1