面试
- ==题目4 合并两个有序链表==
- ==题目5 合并K个升序链表==
- ==题目6 和为K的连续子数组---前缀和+哈希表==
- ==连续子数组表:需要长度大于等于2,和为K的倍数==
- ==题目7:数组中最小的K个数==
- ==题目8:第K个素数/质数==
- ==题目9: 1143: 最长公共子序列---动态规划==
- ==题目10: 3. 无重复字符的最长子串 ---滑动窗口==
- ==题目11: 三数之和---固定first 然后对second 和third 使用双指针办法==
- ==题目12: 最长回文子串-------用双指针的方式 也可以用动态规划 有空看下==
- ==补充--回文子字符串的个数, 也是中心扩展==
- ==补充131:分割回文串==
- ==题目13:全排列II ---包含重复元素==
- ==题目14:全排列无重复==
- ==题目15:最长公共前缀==
- ==题目16:两个栈实现队列==
- ==题目17: 组合总和 leetcode39---注意到这里是可以无限使用次数,而且无重复,所以每一层是新的就是选择和不选择,选择了可以继续选择==
- ==题目18:组合总和------这里每个数字只能使用一次,可能包含重复元素==
- ==题目19:两数之和,是无排序的。如果有序的话就是双指针==
- ==题目20:两数相加2222==
- ==题目22:平衡二叉树==
- ==题目23:二叉树的所有路径==
- ==题目24:判断是否是对称的二叉树==
- ==题目25:镜像二叉树==
- ==题目26:回文数==
- ==题目27:整数反转==
- ==题目28: Z字形变换==
- ==题目29:剑指offer04:二维数组的查找~ 妙啊==
- ==题目30: 连续子数组的最大和==
- ==题目31:根据先序和中序构造二叉树==
- ==32:409 最长回文串==
- ==33:翻转字符串里的单词==
- ==189.旋转数组--补充题----给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。==
- ==路经总和II--输出二叉树路径中等于target的路径==
- ==路经总和I--判断是否存在这样的路==
- ==剑指 Offer II 080. 含有 k 个元素的组合--给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。==
- ==环形链表的入口-- 开头到环形入口走a步,环长度b,慢指针走=nb,快走2nb,慢指针到入口要走a+nb,所以还需要走a,那就快指针到头开始走==
小知识点记录: 哈希表map[j]-- 当减少到0了 不意味着j这个key对应从哈希表中删除了,只不过是value变成0了,map.count(j) 查找的j是对应 key
题目1:判断链表是否有环
#include<bits/stdc++.h>
using namespace std;
struct ListNode{
int val;
ListNode* next;
ListNode():val(0),next(nullptr){}
ListNode(int x):val(x),next(nullptr){}
};
//写个类
class Solution{
public:
/*bool hasCycle(ListNode* head){
if(head==nullptr || head->next==nullptr)
return false;
ListNode* slow=head;
ListNode* fast=head->next;
while(slow!=fast){
if(fast==nullptr || fast->next==nullptr)
return false;
slow=slow->next;
fast=fast->next->next;
}
return true;
}
*/
bool hasCycle(ListNode*head){
if(head==nullptr) return false;
unordered_set<ListNode*> set;
while(head){
if(set.count(head))
return true;
set.insert(head);
head=head->next;
}
return false;
}
};
int main(){
int M=5;
ListNode* dump=new ListNode();
ListNode* head=dump;
for(int i=1;i<=M;i++){
int temp;
cin>>temp;
head->next=new ListNode(temp);
head=head->next;
}
head->next=nullptr;
head=dump->next;
/*Solution *p;
cout<<p->hasCycle(head); */
Solution p;
cout<<p.hasCycle(head);
}
题目2:快速幂运算
class Solution {
public :
double myPow(double x, int n) {
if(n==0) return 1;
long N=n; //防止负数最大反转出错
if(N<0){
x=1/x;
N=-N;
}
double result=1;
while(N>0){
if(N%2==1) result*=x;
N>>=1;
x*=x;
}
return result;
}
};
题目3:反转链表
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* pre=nullptr;
ListNode* curr=head;
while(curr){
ListNode* temp=curr->next;
curr->next=pre;
pre=curr;
curr=temp;
}
return pre;
}
};
//反转双向链表的话
public:
ListNode* reverseList1(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr) {
ListNode* next = curr->next;
//curr->front=next; 如果是反转双向链表的话 前指针指向原来的next指针就行了
curr->next = prev;
prev = curr;
curr = next;
}
//pre->front=nullptr; //不用加 我就是说下。
return prev;
}
题目4 合并两个有序链表
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* dump=new ListNode();
ListNode* temp=dump;
while(l1!=nullptr && l2!=nullptr){
if(l1->val<l2->val){
temp->next=l1;
l1=l1->next;
temp=temp->next;
}
else{
temp->next=l2;
l2=l2->next;
temp=temp->next;
}
}
temp->next= l1==nullptr ? l2:l1;
return dump->next;
}
};
题目5 合并K个升序链表
class Solution {
public:
//合并两个有续链表~
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
ListNode* dump=new ListNode();
ListNode* temp=dump;
while(l1!=nullptr && l2!=nullptr){
if(l1->val<l2->val){
temp->next=l1;
l1=l1->next;
temp=temp->next;
}
else{
temp->next=l2;
l2=l2->next;
temp=temp->next;
}
}
temp->next= l1==nullptr ? l2:l1;
return dump->next;
}
//合并K个有序链表
ListNode* mergeKLists(vector<ListNode*>& lists) {
ListNode *ans = nullptr;
for (int i = 0; i < lists.size(); ++i) {
ans = mergeTwoLists(ans, lists[i]);
}
return ans;
}
};
题目6 和为K的连续子数组—前缀和+哈希表
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> mp;
mp[0] = 1;
int count = 0, pre = 0;
for (auto& x:nums) {
pre += x;
if (mp.count(pre - k)==1) {
count += mp[pre - k];
}
mp[pre]++;
}
return count;
}
};
连续子数组表:需要长度大于等于2,和为K的倍数
class Solution {
public:
bool checkSubarraySum(vector<int>& nums, int k) {
int m = nums.size();
if (m < 2) {
return false;
}
unordered_map<int, int> mp;
mp[0] = -1;
int remainder = 0;
for (int i = 0; i < m; i++) {
remainder = (remainder + nums[i]) % k;
if (mp.count(remainder)) { /如果前面的前缀和 和后面这个弄下来的余数相同,说明后面这一段 被K整除!
int prevIndex = mp[remainder];
if (i - prevIndex >= 2) {
return true;
}
} else
mp[remainder] = i; // key=前缀和,value=索引 注意到只有没出现才会更新下标,所以保证最左下标,所以else必不可少!!!
}
return false;
}
};
题目7:数组中最小的K个数
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
vector<int> vec(k, 0);
if (k == 0) { // 排除 0 的情况
return vec;
}
priority_queue<int> Q;
for (int i = 0; i < k; ++i) {
Q.push(arr[i]);
}
for (int i = k; i < (int)arr.size(); ++i) {
if (Q.top() > arr[i]) {
Q.pop();
Q.push(arr[i]);
}
}
for (int i = 0; i < k; ++i) {
vec[i] = Q.top();
Q.pop();
}
return vec;
}
};
题目8:第K个素数/质数
class Solution {
public:
int getKthMagicNumber(int k) {
priority_queue<long, vector<long>, greater<long>> pq;
pq.push(1);
long res;
while (k > 0) {
res = pq.top();
pq.pop();
while (!pq.empty() && res == pq.top())
pq.pop();
pq.push(res * 3);
pq.push(res * 5);
pq.push(res * 7);
k--;
}
return res;
}
};
题目9: 1143: 最长公共子序列—动态规划
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int m = text1.length(), n = text2.length();
vector<vector<int>> dp(m + 1, vector<int>(n + 1));
for (int i = 1; i <= m; i++) {
char c1 = text1.at(i - 1); //at返回下标为i-1
for (int j = 1; j <= n; j++) {
char c2 = text2[j-1];
if (c1 == c2) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][n];
}
};
题目10: 3. 无重复字符的最长子串 —滑动窗口
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> window;
int left = 0, right = 0;
int res = 0; // 记录结果
while (right < s.size()) {
char c = s[right];
right++;
// 进行窗口内数据的一系列更新
window[c]++;
// 判断左侧窗口是否要收缩
while (window[c] > 1) {
char d = s[left];
left++;
// 进行窗口内数据的一系列更新
window[d]--;
}
// 在这里更新答案
res = max(res, right - left);
}
return res;
};
题目11: 三数之和—固定first 然后对second 和third 使用双指针办法
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> ans;
for (int first = 0; first <n-2; ++first) {
// 需要和上一次枚举的数不相同 用一次就行了
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
//进入双指针环节
int target = -nums[first];
int second = first + 1;
int third = n - 1;
while(second<third) {
if(nums[second] + nums[third]==target){
ans.push_back({nums[first], nums[second], nums[third]});
while(second<third && nums[second] == nums[++second]);//去重
while(second<third && nums[third] == nums[--third]);
}
else if(nums[second] + nums[third] > target){
while(second<third && nums[third] == nums[--third]);
}
else if(nums[second] + nums[third] < target){
while(second<third && nums[second] == nums[++second]);
}
}
}
return ans;
}
};
题目12: 最长回文子串-------用双指针的方式 也可以用动态规划 有空看下
class Solution {
public:
//中心扩展对称即是回文串,在这基础上用双指针
string longestPalindrome(string s) {
int n=s.size(); string res;
for(int i=0;i<n;i++){
string s1=palindrome(s,i,i);
string s2=palindrome(s,i,i+1);
res=res.size()>s1.size() ? res:s1;
res=res.size()>s2.size() ? res:s2;
}
return res;
}
//调用辅助函数
string palindrome(string & s, int l,int r){
while(l>=0 && r<s.size() && s[l]==s[r]){
l--;r++;
}
return s.substr(l+1,r-l-1);
}
};
补充–回文子字符串的个数, 也是中心扩展
class Solution {
public:
int countSubstrings(string s) {
int num = 0;
int n = s.size();
for(int i=0;i<n;i++)//遍历回文中心点
{
for(int j=0;j<=1;j++)//j=0,中心是一个点,j=1,中心是两个点
{
int l = i;
int r = i+j;
while(l>=0 && r<n && s[l--]==s[r++])num++;
}
}
return num;
}
};
补充131:分割回文串
class Solution {
private:
vector<vector<int>> f;
vector<vector<string>> ret;
vector<string> ans;
int n;
public:
void dfs(const string& s, int i) {
if (i == n) {
ret.push_back(ans);
return;
}
for (int j = i; j < n; ++j) { //探索同一个i下不同的j的组合
if (f[i][j]) {
ans.push_back(s.substr(i, j - i + 1));
dfs(s, j + 1); //继续探索当前i往后走的新开始
ans.pop_back();
}
}
}
vector<vector<string>> partition(string s) {
n = s.size();
f.assign(n, vector<int>(n, true));
for (int i = n - 1; i >= 0; --i) {
for (int j = i + 1; j < n; ++j) {
f[i][j] = (s[i] == s[j]) && f[i + 1][j - 1];
}
}
dfs(s, 0);
return ret;
}
};
题目13:全排列II —包含重复元素
class Solution {
vector<int> vis;
vector<int>perm;
vector<vector<int>>ans;
public:
void backtrack(vector<int>& nums) {
if(perm.size()==nums.size()){
ans.emplace_back(perm);
return;
}
for(int i=0; i<nums.size();i++){
if(vis[i] ||(i>0 && nums[i]==nums[i-1] && !vis[i-1]))
continue;
vis[i]=1;
perm.emplace_back(nums[i]);
backtrack(nums);
perm.pop_back();
vis[i]=0;
}
}
//进入主函数
vector<vector<int>> permuteUnique(vector<int>& nums) {
vis.resize(nums.size());
sort(nums.begin(),nums.end());
backtrack(nums);//一开始肯定对第0个元素操作
return ans;
}
};
题目14:全排列无重复
class Solution {
vector<int> vis;
vector<int> track;
vector<vector<int>> res;
public:
void backtrack(vector<int> &Num) {
if(track.size()==Num.size()){
res.push_back(track);
return;
}
for(int i=0; i<Num.size();i++){
if(vis[i]) continue;
vis[i]=1;
track.push_back(Num[i]);
backtrack(Num);
track.pop_back();
vis[i]=0;
}
}
vector<vector<int>> permute(vector<int>& nums) {
vis.resize(nums.size());
backtrack(nums);
return res;
}
};
题目15:最长公共前缀
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
if (!strs.size()) {
return "";
}
string prefix = strs[0];
int count = strs.size();
for (int i = 1; i < count; ++i) {
prefix = longestCommonPrefix(prefix, strs[i]);
if (!prefix.size()) //如果前缀为0,提前退出了
break;
}
return prefix;
}
string longestCommonPrefix(const string& str1, const string& str2) {
int length = min(str1.size(), str2.size());
int index = 0;
while (index < length && str1[index] == str2[index]) {
++index;
}
return str1.substr(0, index); //从0开始index个
}
};
题目16:两个栈实现队列
class CQueue {
stack<int> stack1,stack2; //私有变量 也是全局把可以理解为
public:
//三个函数 初始化、入栈和出栈
CQueue() { //初始化清空栈
while (!stack1.empty()) {
stack1.pop();
}
while (!stack2.empty()) {
stack2.pop();
}
}
void appendTail(int value) {
stack1.push(value); //入栈
}
int deleteHead() { //出栈函数
// 如果第二个栈为空
if (stack2.empty()) {
while (!stack1.empty()) {
stack2.push(stack1.top());
stack1.pop();
}
}
if (stack2.empty()) {
return -1;
} else {
int deleteItem = stack2.top();
stack2.pop();
return deleteItem;
}
}
};
题目17: 组合总和 leetcode39—注意到这里是可以无限使用次数,而且无重复,所以每一层是新的就是选择和不选择,选择了可以继续选择
class Solution {
vector<vector<int>> ans;
vector<int> combine;
public:
void dfs(vector<int>& candidates, int target, int idx) {
if (idx == candidates.size()) { //记录枚举位置
return;
}
if (target == 0) {
ans.emplace_back(combine);
return;
}
// 要么直接跳过,枚举下个
dfs(candidates, target,idx + 1);
// 要么选择当前数 不跳过
//选择的时候如果这个数很大了,那就没啥路走了结束 其实就是无法选择 这个分支结束而已。
if (target - candidates[idx] >= 0) {
combine.emplace_back(candidates[idx]);
dfs(candidates, target - candidates[idx],idx);
combine.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
dfs(candidates, target, 0);
return ans;
}
};
优化方法:
class Solution {
vector<vector<int>> ans;
vector<int> combine;
public:
void dfs(vector<int>& candidates, int target, int idx) {
if(target<0) return;
if (target == 0)
{
ans.emplace_back(combine);
return;
}
for (int i = idx; i < candidates.size(); i++){ //每一层可以继续选择当前元素
target-=candidates[i];
combine.emplace_back(candidates[i]);
dfs(candidates, target,i);
target+=candidates[i];
combine.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
dfs(candidates, target, 0);
return ans;
}
};
题目18:组合总和------这里每个数字只能使用一次,可能包含重复元素
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
vector<bool> used;
void backtracking(vector<int>& candidates, int target,int startIndex) {
if(target<0) return;
if (target==0) {
result.push_back(path);
return;
}
//这里的for是给了他不同的起点。 就是说不走回头路,往后走
for (int i = startIndex; i < candidates.size(); i++) {
// used[i - 1] == true,说明同一树支candidates[i - 1]使用过
// used[i - 1] == false,说明同一树层candidates[i - 1]使用过
// 要对同一树层使用过的元素进行跳过
if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false) {
continue;
}
target -= candidates[i];
path.push_back(candidates[i]);
used[i] = true;
backtracking(candidates, target,i + 1); // 和39.组合总和的区别1,这里是i+1,每个数字在每个组合中只能使用一次
used[i] = false;
target += candidates[i];
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
used.resize(candidates.size(),false);
path.clear();
result.clear();
// 首先把给candidates排序,让其相同的元素都挨在一起。
sort(candidates.begin(), candidates.end());
backtracking(candidates, target,0);
return result;
}
};
题目19:两数之和,是无排序的。如果有序的话就是双指针
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> hashtable;
for (int i = 0; i < nums.size(); ++i) {
if (hashtable.count(target-nums[i]))
return {hashtable[target-nums[i]], i};
hashtable[nums[i]] = i;
}
return {};
}
};
题目20:两数相加2222
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode *head = nullptr, *tail = nullptr;
int carry = 0;
while (l1 || l2) {
int n1 = l1 ? l1->val: 0;
int n2 = l2 ? l2->val: 0;
int sum = n1 + n2 + carry;
if (!head) {
head = tail = new ListNode(sum % 10);
} else {
tail->next = new ListNode(sum % 10);
tail = tail->next;
}
carry = sum / 10;
if (l1) {
l1 = l1->next;
}
if (l2) {
l2 = l2->next;
}
}
if (carry > 0) {
tail->next = new ListNode(carry);
}
return head;
}
};
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
return addTwoNumbersCore(l1, l2, 0);
}
ListNode* addTwoNumbersCore(ListNode* l1, ListNode* l2, int carry) {
if (!l1 && !l2 && carry == 0) {
// 当输入的节点均为null且无需处理进位时,结束
return nullptr;
}
int val = carry + (l1 ? l1 -> val : 0) + (l2 ? l2 -> val : 0); // 计算当前的和
ListNode* res = new ListNode(val % 10);
res -> next = addTwoNumbersCore((l1 ? l1 -> next : nullptr), (l2 ? l2 -> next : nullptr), val / 10);
return res;
}
};
题目20:二叉树的最大深度
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == nullptr) return 0;
return max(maxDepth(root->left), maxDepth(root->right)) + 1;
}
};
题目22:平衡二叉树
class Solution {
public:
int height(TreeNode* root) {
if (root == NULL) {
return 0;
} else {
return max(height(root->left), height(root->right)) + 1;
}
}
bool isBalanced(TreeNode* root) {
if (root == NULL) {
return true;
} else {
return abs(height(root->left) - height(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right);
}
}
};
题目23:二叉树的所有路径
class Solution {
public:
void construct_paths(TreeNode* root, string path, vector<string>& paths) {
if (root != nullptr) {
path += to_string(root->val);
if (root->left == nullptr && root->right == nullptr) { // 当前节点是叶子节点
paths.push_back(path); // 把路径加入到答案中
} else {
path += "->"; // 当前节点不是叶子节点,继续递归遍历
construct_paths(root->left, path, paths);
construct_paths(root->right, path, paths);
}
}
}
vector<string> binaryTreePaths(TreeNode* root) {
vector<string> paths;
construct_paths(root, "", paths);
return paths;
}
};
题目24:判断是否是对称的二叉树
class Solution {
public:
bool isSymmetric(TreeNode* root) {
if(root==nullptr) return true;
return recur(root->left,root->right);
}
bool recur(TreeNode* root1, TreeNode* root2){
if(!root1 && !root2) return true;
if(!root1 || !root2 ||root1->val!=root2->val) return false;
return recur(root1->left,root2->right) && recur(root1->right,root2->left);
}
};
题目25:镜像二叉树
class Solution {
public:
TreeNode* mirrorTree(TreeNode* root) {
if (root == nullptr) {
return nullptr;
}
TreeNode* left = mirrorTree(root->left);
TreeNode* right = mirrorTree(root->right);
root->left = right;
root->right = left;
return root;
}
};
题目26:回文数
class Solution {
public:
bool isPalindrome(int x) {
// 特殊情况:
// 如上所述,当 x < 0 时,x 不是回文数。
// 同样地,如果数字的最后一位是 0,为了使该数字为回文,
// 则其第一位数字也应该是 0
// 只有 0 满足这一属性
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
int revertedNumber = 0;
while (x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x /= 10;
}
// 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
// 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
// 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
return x == revertedNumber || x == revertedNumber / 10;
}
};
class Solution {
public:
bool isPalindrome(int x) {
string s=to_string(x);
int n=s.size();
int left=0,right=n-1;
while(left<right){
if(s[left]==s[right]){
left++;right--;
}
else
return false;
}
return true;
}
};
题目27:整数反转
class Solution {
public:
int reverse(int x) {
long long r = 0;
while (x) {
r = r * 10 + x % 10;
x /= 10;
}
if (abs(r) > INT_MAX) return 0;
return r;
}
};
```cpp
class Solution {
public:
int reverse(int x) {
int r = 0;
while (x) {
if (r > 0 && r > (INT_MAX - x % 10) / 10) return 0;
if (r < 0 && r < (INT_MIN - x % 10) / 10) return 0;
r = r * 10 + x % 10;
x /= 10;
}
return r;
}
};
题目28: Z字形变换
class Solution {
public:
string convert(string s, int numRows) {
if (numRows == 1) return s;
vector<string> rows(min(numRows, int(s.size())));
int curRow = 0;
bool goingDown = false;
for (char c : s) {
rows[curRow] += c;
if (curRow == 0 || curRow == numRows - 1) goingDown = !goingDown;
curRow += goingDown ? 1 : -1;
}
string ret;
for (string row : rows) ret += row;
return ret;
}
};
题目29:剑指offer04:二维数组的查找~ 妙啊
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
int i = matrix.size() - 1, j = 0;
while(i >= 0 && j < matrix[0].size())
{
if(matrix[i][j] > target) i--;
else if(matrix[i][j] < target) j++;
else return true;
}
return false;
}
};
题目30: 连续子数组的最大和
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int pre = 0, maxAns = nums[0];
for (const auto &x: nums) {
pre = max(pre + x, x);
maxAns = max(maxAns, pre);
}
return maxAns;
}
};
题目31:根据先序和中序构造二叉树
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
//很明显此题需要递归
return newtree(preorder,0,preorder.size()-1,inorder,0,inorder.size()-1);
}
//构造调用函数
TreeNode* newtree(vector<int>& preorder,int l1,int r1, vector<int>& inorder,int l2,int r2){
if(l1>r1)
return nullptr;
TreeNode* root=new TreeNode();
root->val=preorder[l1];
//要找到根节点在中序遍历中的位置
int index=0;int length=0;
for(int i=l2;i<=r2;i++){
if(inorder[i]==root->val){
index=i;
length=index-l2;
break;
}
}
//构建左右子树
root->left=newtree(preorder,l1+1,l1+length,inorder,l2,index-1);
root->right=newtree(preorder,l1+length+1,r1,inorder,index+1,r2);
return root;
}
};
32:409 最长回文串
class Solution {
public:
int longestPalindrome(string s) {
unordered_map<char, int> count;
int ans = 0;
for (char c : s)
++count[c];
for (auto p : count) {
int v = p.second;
ans += v / 2 * 2;
if (v % 2 == 1 and ans % 2 == 0)
++ans;
}
return ans;
}
};
33:翻转字符串里的单词
利用 stringstream 把字符串s 转化为输入流 此时我们自定义的ssin就可以向cin一样去使用
我们自定义的ssin和cin一样, 每次读取时都会跳过空格
class Solution {
public:
string reverseWords(string s) {
string s1[1000], s2;
int i = 0;
stringstream ssin(s);
while(ssin>>s1[i])
i++;
for(int j = i - 1; j > 0; j--)
s2+=s1[j]+" ";
s2+=s1[0];
return s2;
}
};
189.旋转数组–补充题----给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int n = nums.size();
vector<int> newArr(n);
for (int i = 0; i < n; ++i) {
newArr[(i + k) % n] = nums[i]; //比如数组有8位,这个8就放到开头的地方~
}
nums.assign(newArr.begin(), newArr.end());//容器赋值运算,将new中的值送给nums
};
方法2,用o(1)的空间复杂度
https://leetcode-cn.com/problems/rotate-array/solution/xuan-zhuan-shu-zu-by-leetcode-solution-nipk/
class Solution {
public:
void reverse(vector<int>& nums, int start, int end) {
while (start < end) {
swap(nums[start], nums[end]);
start += 1;
end -= 1;
}
}
void rotate(vector<int>& nums, int k) {
k %= nums.size();
reverse(nums, 0, nums.size() - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, nums.size() - 1);
}
};
路经总和II–输出二叉树路径中等于target的路径
class Solution {
public:
vector<vector<int>> ret;
vector<int> path;
void dfs(TreeNode* root, int targetSum) {
if (root == nullptr) {
return;
}
path.emplace_back(root->val);
targetSum -= root->val;
if (root->left == nullptr && root->right == nullptr && targetSum == 0) {
ret.emplace_back(path);
}
dfs(root->left, targetSum);
dfs(root->right, targetSum);
path.pop_back();
}
vector<vector<int>> pathSum(TreeNode* root, int targetSum) {
dfs(root, targetSum);
return ret;
}
};
路经总和I–判断是否存在这样的路
class Solution {
public:
bool hasPathSum(TreeNode *root, int sum) {
if (root == nullptr) {
return false;
}
if (root->left == nullptr && root->right == nullptr) {
return sum == root->val;
}
return hasPathSum(root->left, sum - root->val) ||
hasPathSum(root->right, sum - root->val);
}
};
队列的解:
class Solution {
public:
bool hasPathSum(TreeNode *root, int sum) {
if (root == nullptr) {
return false;
}
queue<TreeNode *> que_node;
queue<int> que_val;
que_node.push(root);
que_val.push(root->val);
while (!que_node.empty()) {
TreeNode *now = que_node.front();
int temp = que_val.front();
que_node.pop();
que_val.pop();
if (now->left == nullptr && now->right == nullptr) {
if (temp == sum) {
return true;
}
continue;
}
if (now->left != nullptr) {
que_node.push(now->left);
que_val.push(now->left->val + temp);
}
if (now->right != nullptr) {
que_node.push(now->right);
que_val.push(now->right->val + temp);
}
}
return false;
}
};
剑指 Offer II 080. 含有 k 个元素的组合–给定两个整数 n 和 k,返回 1 … n 中所有可能的 k 个数的组合。
class Solution {
private:
void helper(int i, int n, int k, vector<vector<int>>& ret, vector<int>& cur) {
if (cur.size() == k) {
ret.emplace_back(cur);
return;
}
// i 超界
if (i > n) {
return;
}
// 不加入 i
helper(i + 1, n, k, ret, cur);
// 加入 i
cur.push_back(i);
helper(i + 1, n, k, ret, cur);
cur.pop_back();
}
public:
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> ret;
vector<int> cur;
helper(1, n, k, ret, cur);
return ret;
}
};
环形链表的入口-- 开头到环形入口走a步,环长度b,慢指针走=nb,快走2nb,慢指针到入口要走a+nb,所以还需要走a,那就快指针到头开始走
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode *fast = head, *slow = head;
while (true) {
if (fast == nullptr || fast->next == nullptr) return nullptr;
fast = fast->next->next;
slow = slow->next;
if (fast == slow) break;
}
fast = head;
while (slow != fast) {
slow = slow->next;
fast = fast->next;
}
return fast;
}
};