编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。
class Solution{
public:
void reverseString(vector<char>& s) {
if(s.size()<=1) return;
int i=0,j=s.size()-1;
while(j>i){
swap(s[i],s[j]);
i++;
j--;
}
}
};
class Solution {
public:
void reverseString(vector<char>& s) {
if(s.size()<=1) return;
reverse(s.begin(),s.end());
}
};
class Solution{
public:
void reverseHelper(vector<char>& s,int pos,int len){
if(pos>=len/2) return;
swap(s[pos],s[len-pos-1]);
reverseHelper(s,pos+1,len);
}
void reverseString(vector<char>& s) {
if(s.size()<=1) return;
reverseHelper(s,0,s.size());
}
};
将给定的链表中每两个相邻的节点交换一次,返回链表的头指针
例如:给出1->2->3->4,你应该返回链表2->1->4->3。
你给出的算法只能使用常量级的空间。你不能修改列表中的值,只能修改节点本身。
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if(!head||!head->next) return head;
ListNode* p=head;
head=p->next;
p->next=head->next;
head->next=p;
//迭代之后要和之前的链表连接起来!!!
p->next=swapPairs(p->next);
return head;
}
};
给定一个值n,请生成所有的存储值1…n.的二叉搜索树(BST)的结构
例如:给定n=3,你的程序应该给出下面五种不同的二叉搜索树
[
[1,null,3,2],
[3,2,null,1],
[3,1,null,null,2],
[2,1,3],
[1,null,2,null,3]
]
class Solution {
public:
vector<TreeNode*> generateTreesHelper(int start,int end){
vector<TreeNode*> Trees;
if(start>end){
Trees.emplace_back(nullptr);
return Trees;
}
for(int i=start;i<=end;i++){
vector<TreeNode*> leftTrees=generateTreesHelper(start,i-1);
vector<TreeNode*> rightTrees=generateTreesHelper(i+1,end);
//从左子树集合中选出一颗左子树,右边相同操作,拼接到根上
for(auto& left:leftTrees){
for(auto& right:rightTrees){
TreeNode* cur=new TreeNode(i);
cur->left=left;
cur->right=right;
Trees.emplace_back(cur);
}
}
}
return Trees;
}
vector<TreeNode*> generateTrees(int n) {
return generateTreesHelper(1,n);
}
};
class Solution {
public:
int fib(int N) {
if(0==N) return 0;
if(1==N) return 1;
return fib(N-1)+fib(N-2);
}
};
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
说明:
如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
滑动窗口算法的思路是这样:
1、我们在字符串 S 中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引左闭右开区间 [left, right) 称为一个「窗口」。
2、我们先不断地增加 right 指针扩大窗口 [left, right),直到窗口中的字符串符合要求(包含了 T 中的所有字符)。
3、此时,我们停止增加 right,转而不断增加 left 指针缩小窗口 [left, right),直到窗口中的字符串不再符合要求(不包含 T 中的所有字符了)。同时,每次增加 left,我们都要更新一轮结果。
4、重复第 2 和第 3 步,直到 right 到达字符串 S 的尽头。
需要思考的问题:
1、当移动 right 扩大窗口,即加入字符时,应该更新哪些数据?
增加window计数器以及window里面的元素;
2、什么条件下,窗口应该暂停扩大,开始移动 left 缩小窗口?
当valid满足need的即所有元素都出现在窗口中;
3、当移动 left 缩小窗口,即移出字符时,应该更新哪些数据?
减少window计数器以及window里面的元素;
4、我们要的结果应该在扩大窗口时还是缩小窗口时进行更新?
应该在收缩窗口的时,且在收缩之前更新最终结果。
作者:labuladong 力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-window-substring/solution/hua-dong-chuang-kou-suan-fa-tong-yong-si-xiang-by-/
窗口中一直只有T中包含的字符,是由right和left记录S中包含T中所有字符的子串的起始
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char,int> need,window;
for(char c:t) need[c]++;
int left=0,right=0;
int valid=0;
//记录最小覆盖子串的起始索引及长度
int start=0,len=INT_MAX;
while(right<s.size()){
char c=s[right];
//窗口右移
right++;
//更新窗口相关的数据
if(need.count(c)){//need中存在c对应的字符
window[c]++;
if(window[c]==need[c]) valid++;
}
//判断左窗口是否要收缩
while(valid==need.size()){
//更新最小覆盖子串
if(right-left<len){
start=left;
len=right-left;
}
//d记录将移出窗口的字符
char d=s[left];
left++;//窗口左移
//进行窗口内数据的一系列更新
if(need.count(d)){
if(window[d]==need[d]) valid--;
window[d]--;
}
}
}
return len==INT_MAX?"":s.substr(start,len);
}
};
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例1:
输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”).
示例2:
输入: s1= “ab” s2 = “eidboaoo”
输出: False
class Solution {
public:
bool checkInclusion(string s1, string s2) {
unordered_map<char,int> need,window;
for(char c:s1) need[c]++;
int right=0,left=0;
int valid=0;
while(right<s2.size()){
char c=s2[right];
right++;
if(need.count(c)){
window[c]++;
if(window[c]==need[c]) valid++;
}
//移动 left 缩小窗口的时机是窗口大小大于 t.size() 时,应为排列嘛,显然长度应该是一样的
while(right-left>=s1.size()){
if(valid==need.size()) return true;//因为map是hush表,所以若valid==need.size(),则里面的字符一定为need里面字符的排序
char d=s2[left];
left++;
if(need.count(d)){
if(window[d]==need[d]) valid--;
window[d]--;
}
}
}
return false;
}
};
给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:字母异位词指字母相同,但排列不同的字符串。不考虑答案输出的顺序。
示例 1:
输入:s: “cbaebabacd” p: “abc”
输出:[0, 6]
解释:起始索引等于 0 的子串是 “cba”, 它是 “abc” 的字母异位词。起始索引等于 6 的子串是 “bac”, 它是 “abc” 的字母异位词。
示例 2:
输入:s: “abab” p: “ab”
输出:[0, 1, 2]
解释:起始索引等于 0 的子串是 “ab”, 它是 “ab” 的字母异位词。起始索引等于 1 的子串是 “ba”, 它是 “ab” 的字母异位词。起始索引等于 2 的子串是 “ab”, 它是 “ab” 的字母异位词。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
unordered_map<char,int> need,window;
for(char c:p) need[c]++;
int left=0,right=0;
int valid=0;
vector<int> res;
while(right<s.size()){
char c=s[right];
right++;
if(need.count(c)){
window[c]++;
if(window[c]==need[c]) valid++;
}
while(right-left>=p.size()){
if(valid==need.size()) res.emplace_back(left);
char d=s[left];
left++;
if(need.count(d)){
if(window[d]==need[d]) valid--;
window[d]--;
}
}
}
return res;
}
};
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:
输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:
输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char,int> window;
int left=0,right=0;
int Longest=0;
while(right<s.size()){
char c=s[right];
right++;
window[c]++;
//c在窗口中出现不止一次,证明窗口要收缩了
while(window[c]>1){
char d=s[left];
left++;
window[d]--;
}
Longest=max(Longest,right-left);
}
return Longest;
}
};