面试题库2
- ==判断括号是否合法 ()(()() || (()()) || ())() ||()()==
- ==括号生成--给定n个括号对,求能组成几个括号组合==
- ==输入括号,求连续的最长满足成对的括号长度 --lc32:最长有效括号==
- ==旋转数组--二分法扩展!---整数数组 nums 按升序排列,数组中的值 互不相同,把数组尾部一部分旋转到前面,然后在数组中搜索target的下标 [4,5,6,7,0,1,2], target = 0 输出5==
- ==经典二分查找--在排序数组中查找数组的前后索引,或者出现次数 5 7 7 8 8 10 target=8 输出2==
- ==跳跃游戏==
- ==下一个排列==
- ==两两交换链表中的节点==
- ==最长递增子序列的个数-不连续~13547 2组 1347 1357==
- ==最长回文子序列"bbbab"---bbbb动态规划==
- ==128-最长连续序列--[100,4,200,1,3,2] --输出 1 2 3 4 所以是4 这里的连续是数值而不是顺序==
- ==贪心-最长连续递增序列--连续 nums =[1,3,5,4,7] 输出3 因为1 3 5==
- ==最长递增子序列长度--不连续 nums = [10,9,2,5,3,7,101,18] ---输出4 2 3 7 101==
- ==剑指offer03 数组中重复的数字-----在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。==
- ==H指数-二分查==
- ==合并两个有序数组==
- ==删除链表的某个节点==
- ==求一个数所有的质因子==
- ==根据层序遍历数组构造二叉树==
- ==根据前序遍历数组构造二叉树==
- ==根据后续遍历数组构造二叉树==
- ==自己定义链表结构体实现删除倒数第N个链表j节点==
- ==自己定义链表结构体实现链表反转==
- ==自己定义链表结构体实现环形链表==
- ==自己定义链表结构体实现链表相交查找==
- ==组中超过一半的元素-- 哈希表,排序,摩尔投票==
- ==返回两个数组的中位数,2方法==
- ==请你计算并返回可以凑成总金额的硬币组合数。--无限个==
- ==零钱兑换I--计算并返回可以凑成总金额所需的 最少的硬币个数 。无限个==
- ==01背包~~~==
- ==完全背包~~就是01顺序换了==
- ==搜索插入位置,给定target看在排序的原数组中在哪里应该下标,如果找不到就可能是0 或者n安排==
- ==最接近的三数之和==
- ==盛水最多的容器==
- ==翻转字符串里的单词--用方法==
- ==乘积最大的连续子数组==
- ==打家劫舍II 环形的==
- ==顺时针打印矩阵==
- ==折叠链表==
- ==对getline的数字赋值给数组 ,以空格为界限,也可以修改为逗号 都行==
- ==二叉树的前序遍历==
- ==根据字符串出现的频率排序输出==
- ==链表求和==
- ==不用哈希表求去字符串重abcdab--- abcd==
- ==不用哈希表找出第一个不重复的字符==
- ==带随机指针链表的深拷贝--或者就是链表的深拷贝方法==
- ==链表中每K个一组反转链表,不足K个就不反转==
- ==MySQL建表~==
- ==求最大公约数和最小公倍数==
- ==8. 字符串转换整数 (atoi)==
- ==旋转图像--顺时针90°==
- ==字母异位词分组--将异位词放到一个组里分别输出==
- ==93.复原IP地址----3位数,4组,不能0补位开头,.隔开==
- ==相同的树--给定两个树头节点,判断是否树是否相同==
- ==剑指 Offer II 093. 最长斐波那契数列==
判断括号是否合法 ()(()() || (()()) || ())() ||()()
class Parenthesis {
public:
bool chkParenthesis(string A, int n) {
// write code here
int num = 0;
for (int i = 0; i < n; i++)
{
if (A[i] == '(')
num++;
else if (A[i] == ')')
num--;
else
return false;
if (num < 0)
return false;
}
if (num == 0)
return true;
else
return false;
}
};
括号生成–给定n个括号对,求能组成几个括号组合
class Solution {
vector<string>res;
public:
vector<string> generateParenthesis(int n) {
dfs("",n,n);
return res;
}
void dfs(string s, int left, int right) { //记录left和right括号的个数
if(left==0 && right==0){
res.push_back(s);
return;
}
if(left==right){
dfs(s+"(",left-1,right);
}
else if(left<right){
if(left>0)
dfs(s+"(",left-1,right);
dfs(s+")",left,right-1);
}
}
};
输入括号,求连续的最长满足成对的括号长度 --lc32:最长有效括号
#include<bits/stdc++.h>
using namespace std;
//()(()( ||||||||| ()(())(
int main(){
string s;
getline(cin,s);
int num=0,ans=0;
int n=s.size();
int maxone=0;
for(int i=0;i<n;i++)
{
ans=0;
num=0;
if(s[i]==')') continue;
if(s[i]=='(') num++;
for(int j=i+1;j<n;j++)
{
if(s[j]=='(') num++;
if(s[j]==')') num--;
if(num<0) break;
if(num==0)
{
ans=j-i+1;
}
}
maxone=max(ans,maxone);
}
cout<<maxone;
}
旋转数组–二分法扩展!—整数数组 nums 按升序排列,数组中的值 互不相同,把数组尾部一部分旋转到前面,然后在数组中搜索target的下标 [4,5,6,7,0,1,2], target = 0 输出5
class Solution {
public:
int search(vector<int>& nums, int target) {
int n = (int)nums.size();
if (!n) {
return -1;
}
if (n == 1) {
return nums[0] == target ? 0 : -1;
}
int l = 0, r = n - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target) return mid;
if (nums[0] <= nums[mid]) {
if (nums[0] <= target && target < nums[mid]) { //不仅要mid比目标值大,而且还要target在num[0]之上。不然可能target很小在右侧
r = mid - 1;
} else {
l = mid + 1;
}
} else {
if (nums[mid] < target && target <= nums[n - 1]) { //同理 不仅是mid比target小l上去,如果target太大反而mid要减少
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return -1;
}
};
经典二分查找–在排序数组中查找数组的前后索引,或者出现次数 5 7 7 8 8 10 target=8 输出2
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0,right=nums.size()-1;
//查找右边界,让i不断增加
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]<=target) left++;
else right--;
}
int j=left; //j记录了右边界+1
if(right<0 || nums[right]!=target) return 0; //针对太大或者太小的情况
//查找左边界,让右边界不断移动出界
left=0,right=nums.size()-1;
while(left<=right){
int mid=left+(right-left)/2;
if(nums[mid]>=target) right--;
else left++;
}
int i=right; //right记录了左边界-1
return j-i-1; //如果是返回索引 return{i+1,j-1};
}
};
跳跃游戏
class Solution {
public:
int jump(vector<int>& nums) {
int maxPos = 0, n = nums.size(), end = 0, step = 0;
for (int i = 0; i < n - 1; ++i) { //因为在n-1这个点肯定能跳到结尾了,因为我们设置了maxpos 记录每个位置能跳的最大距离
maxPos = max(maxPos, i + nums[i]);
if (i == end) { //如果到了上一次跳跃的临界点 那就看下哪里是跳的远的,设置下一次的临界点,step++ 然后在这个临界点内找最远的点跳
end = maxPos; //当end超过n-1就不会跳了哈哈 end是确定本次的最远跳跃点,但是不一定是这边
++step; //达到临界点了,我看在开头到临界点区域我能跳最远的距离,我跳选择最远的点跳。
}
}
return step;
}
};
下一个排列
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int i = nums.size() - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--; //找出第一个变小的数 ==找较小数
}
if (i >= 0) {
int j = nums.size() - 1;
while (j >= 0 && nums[i] >= nums[j]) { //因为 i右侧是降序排列,我要找较大的数但是尽可能小 找到第一个j比i大的~
j--;
}
swap(nums[i], nums[j]); //交换
}
reverse(nums.begin() + i + 1, nums.end()); //因为i后面的数字都比他大,降序排列 那我反转变成升序,就是最小值了~
}
};
两两交换链表中的节点
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
if (head == nullptr || head->next == nullptr)
{
return head;
}
ListNode* newHead = head->next;
ListNode* ne=newHead->next;
newHead->next = head;
head->next = swapPairs(ne);//主要
return newHead;
}
};
最长递增子序列的个数-不连续~13547 2组 1347 1357
class Solution {
public:
int findNumberOfLIS(vector<int>& nums) {
if (nums.size() <= 1) return nums.size();
vector<int> dp(nums.size(), 1);
vector<int> count(nums.size(), 1);
int maxCount = 0;
for (int i = 1; i < nums.size(); i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) {
if (dp[j] + 1 > dp[i]) { //如果j结尾的长度+1已经大于我现在i结尾了。这意味着dp[i]的情况要易主了 dp[i]选择更大的长度为dp[j]+1 个数也转变为j处的。
dp[i] = dp[j] + 1;
count[i] = count[j];
} else if (dp[j] + 1 == dp[i]) { //注意dp[j]是j结尾的,然后组合就是j后面再街上i 所以不同的j就是不同的情况 dp是长度~~~~~ j之后i j之后i 所以每组不同的累加
count[i] += count[j];//注意上面一定要用else if 因为你对dp修改了
}
}
if (dp[i] > maxCount) maxCount = dp[i];
}
}
int result = 0;
for (int i = 0; i < nums.size(); i++) {
if (maxCount == dp[i]) result += count[i];
}
return result;
}
};
最长回文子序列"bbbab"—bbbb动态规划
class Solution {
public:
int longestPalindromeSubseq(string s) {
int n = s.length();
vector<vector<int>> dp(n, vector<int>(n));
for (int i = n - 1; i >= 0; i--) {
dp[i][i] = 1;
char c1 = s[i];
for (int j = i + 1; j < n; j++) {
char c2 = s[j];
if (c1 == c2) {
dp[i][j] = dp[i + 1][j - 1] + 2;
} else {
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]); //从i大的地方走
}
}
}
return dp[0][n - 1];
}
};
128-最长连续序列–[100,4,200,1,3,2] --输出 1 2 3 4 所以是4 这里的连续是数值而不是顺序
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_set<int> num_set;
for (const int& num : nums) {
num_set.insert(num);
}
int longestStreak = 0;
for (const int& num : num_set) {
if (!num_set.count(num - 1)) {
int currentNum = num;
int currentStreak = 1;
while (num_set.count(currentNum + 1)) {
currentNum += 1;
currentStreak += 1;
}
longestStreak = max(longestStreak, currentStreak);
}
}
return longestStreak;
}
};
贪心-最长连续递增序列–连续 nums =[1,3,5,4,7] 输出3 因为1 3 5
class Solution { //说白了这道题核心是确定 start和 i作为终点,一旦i不符合条件start等于i继续走
public:
int findLengthOfLCIS(vector<int>& nums) {
int ans = 0;
int n = nums.size();
int start = 0;
for (int i = 0; i < n; i++) {
if (i > 0 && nums[i] <= nums[i - 1]) {
start = i; //可以说是贪心把 一旦下降了,那就把start移动到下降的地方不断贪心增加
}
ans = max(ans, i - start + 1);
}
return ans;
}
};
最长递增子序列长度–不连续 nums = [10,9,2,5,3,7,101,18] —输出4 2 3 7 101
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n =nums.size();
if (n == 0) {
return 0;
}
vector<int> dp(n, 0);
for (int i = 0; i < n; ++i) {
dp[i] = 1;
for (int j = 0; j < i; ++j) {
if (nums[j] < nums[i]) {
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
return *max_element(dp.begin(), dp.end());
}
};
剑指offer03 数组中重复的数字-----在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size()-1;i++)
if(nums[i]==nums[i+1])
return nums[i];
return -1;
}
};
class Solution { //这道题简单来写可以用sort 然后nums[i]==nums[i+1]判断或者哈希表
public:
int findRepeatNumber(vector<int>& nums) {
int i = 0;
while(i < nums.size()) {
if(nums[i] == i) {
i++;
continue;
}
if(nums[nums[i]] == nums[i])
return nums[i];
swap(nums[i],nums[nums[i]]); //因为 nums[nums[i]] != nums[i] 那就一直交换到相同 前提是肯定存在重复元素
}
return -1;
}
};
H指数-二分查
//H指数--二分查找
class Solution {
public:
int hIndex(vector<int>& cit) {
int n=cit.size();
int l = 0, r = n;
while(l < r){
int mid = (l+r+1)/2; //+1是为了避免当n=1时,程序陷入死循环
int t = 0;
for(auto x:cit){
if(x >= mid) t ++;
}
if(t < mid) r = mid - 1; //此时答案不满足,收缩右边界
else l = mid; //此时满足,扩大左边界
}
return l;
}
};
合并两个有序数组
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
vector<int>res(m+n);
int index=0,i=0,j=0;
while(i<m && j<n){
if(nums1[i]<=nums2[j]){
res[index++]=nums1[i++];
}
else
res[index++]=nums2[j++];
}
for(;i<m;)
res[index++]=nums1[i++];
for(;j<n;)
res[index++]=nums2[j++];
//
for(int i=0;i<m+n;i++)
nums1[i]=res[i];
}
};
删除链表的某个节点
class Solution {
public:
ListNode* deleteNode(ListNode* head, int val) {
if(head->val == val) return head->next;
ListNode *pre = head, *cur = head->next;
while(cur != nullptr && cur->val != val) {
pre = cur;
cur = cur->next;
}
if(cur != nullptr) pre->next = cur->next;
return head;
}
};
class Solution {
public:
ListNode* deleteNode(ListNode* head, int val) {
ListNode*dump=new ListNode(0);
dump->next=head;
ListNode*temp=dump;
while(head){
if(head->val==val){
temp->next=head->next;
}
head=head->next;
temp=temp->next;
}
return dump->next;
}
};
求一个数所有的质因子
#include
using namespace std;
int main()
{
int n,i=2;
cin>>n;
while(i<=n)
{
if(n%i==0)
{
cout<<i<<' ';
n=n/i;
while(n%i==0)
n=n/i;
}
else
++i;
}
}
根据层序遍历数组构造二叉树
//程序功能:输入一组数据是二叉树的层序遍历,要求根据数据创建二叉树,然后用层序遍历、前、中、后序来输出二叉树
#include<bits/stdc++.h>
using namespace std;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode():val(0),left(NULL),right(NULL){} //这样允许我们可以使用 new TreeNode 或者 new TreeNode()
TreeNode(int x):val(x),left(NULL),right(NULL){} //这里就简单这么赋值把
};
TreeNode* creatBinTree(vector<string> & arr) ;
void printBinTree_bfs(TreeNode* head); //声明下二叉树输出函数
int Final_Task(TreeNode* head);
int main() {
vector<string> a;
cout<<"Please enter the numbers: "<<endl;
string str; getline(cin,str);
stringstream ss(str); string temp;
while(getline(ss,temp,' '))
{
a.push_back(temp);
}
TreeNode* head = creatBinTree(a); //注意到这样就行了,虽然里面是创建了形参,但是我最终给他return出来了两个地址对上了地址的改变还是存在的!!!
printBinTree_bfs(head);
}
//子程序1:-------------------------按照层序遍历构造二叉树--二叉树构造程序
TreeNode* creatBinTree(vector<string> & arr) {
queue<TreeNode*> q;
if (arr.empty()) return nullptr;
TreeNode* head =new TreeNode; //创建头节点 注意到结构体的赋值用new一般是针对指针式样结构体 如链表和树这种
head->val = stoi(arr[0]);
q.push(head);
int i = 1;
//层序遍历--只要非空就进入循环啊
while (!q.empty()) {
TreeNode* temp = q.front();
q.pop();
if (i < arr.size()) {
if(arr[i]=="nullptr") temp->left=nullptr;
else{
temp->left = new TreeNode(stoi(arr[i]));
q.push(temp->left);
}
i++; //数组后移
}
else temp->left = nullptr;
//再弄右孩子
if (i < arr.size()) {
if(arr[i]=="nullptr")
temp->right=nullptr;
else{
temp->right = new TreeNode(stoi(arr[i]));
q.push(temp->right); //右孩子入队
}
i++; //数组后移
}
else temp->right = nullptr;
}
return head; //最后队列为空就出while,返回头节点
}
//子程序2:------------------------层序遍历输出二叉树
void printBinTree_bfs(TreeNode* head) {
queue<TreeNode*> q;
if (head == nullptr) {
cout << "TreeNode is empty!" <<endl;
return;
}
q.push(head);
TreeNode* b;
while (!q.empty()) {
b = q.front(); //拿到队头,队头出队
q.pop();
cout <<b->val<< endl; //打印对头的数据
if (b->left)
q.push(b->left);
if (b->right)
q.push(b->right);
}
}
///自己的程序
/*
Final_Task(TreeNode*head){
//比如输出二叉树的最大深度
}
*/
根据前序遍历数组构造二叉树
//根据前序遍历构造二叉树~~~~~~~~~~~~~~~~~~~
#include<bits/stdc++.h>
using namespace std;
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode():val(0),left(nullptr), right(nullptr){}
TreeNode(int x):val(x),left(nullptr), right(nullptr){}
};
int index=0;
TreeNode* creatBinTree(vector<string> & arr);
int main(){
string s;
getline(cin,s);
stringstream ss(s);
string temp;
vector<string>arr;
while(getline(ss,temp,' '))
arr.push_back(temp);
//完成输入
TreeNode* head=creatBinTree(arr);
//1 nullptr nullptr nullptr一定要有
}
TreeNode* creatBinTree(vector<string> & arr) {
if(arr.size()==0)
return nullptr;
string value=arr[index];
index++;
if (value =="nullptr")
return nullptr;
TreeNode* head = new TreeNode(stoi(value));
head->left = creatBinTree(arr);
head->right= creatBinTree(arr);
return head;
}
根据后续遍历数组构造二叉树
//程序功能:输入一组数据是二叉树的后序遍历,根据后续遍历来构建二叉树
#include<bits/stdc++.h>
using namespace std;
int index=0;
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode():val(0),left(NULL),right(NULL){} //这样允许我们可以使用 new TreeNode 或者 new TreeNode()
TreeNode(int x):val(x),left(NULL),right(NULL){} //这里就简单这么赋值把
};
TreeNode* creatBinTree(vector<string> & arr) ;
void printBinTree_bfs(TreeNode* head); //声明下二叉树输出函数
int main() {
vector<string> a;
cout<<"Please enter the numbers: "<<endl;
string str; getline(cin,str);
stringstream ss(str); string temp;
while(getline(ss,temp,' '))
{
a.push_back(temp);
}
reverse(a.begin(),a.end());
TreeNode* head = creatBinTree(a); //注意到这样就行了,虽然里面是创建了形参,但是我最终给他return出来了两个地址对上了地址的改变还是存在的!!!
}
//子程序1:-------------------------按照后续遍历构造二叉树--二叉树构造程序
TreeNode* creatBinTree(vector<string> & arr) {
if(arr.size()==0)
return nullptr;
string value=arr[index];
index++;
if (value =="nullptr") {
return nullptr;
}
TreeNode* head = new TreeNode(stoi(value));
head->right= creatBinTree(arr); //注意到我这边用了 根、右、左的顺序。输出的是相反的 所以我将原来数组反转就能负负得正了。
head->left = creatBinTree(arr);
return head;
}
//子程序2:------------------------层序遍历输出二叉树
void printBinTree_bfs(TreeNode* head) {
queue<TreeNode*> q;
//树为空
if (head == nullptr) {
cout << "TreeNode is empty!" <<endl;
return;
}
//头节点入队
q.push(head);
TreeNode* b; //工具人b
while (!q.empty()) {
b = q.front(); //拿到队头,队头出队
q.pop();
cout <<b->val<< endl; //打印对头的数据
//对头的左孩子存在就入队
if (b->left) {
q.push(b->left);
}
//对头的右孩子存在就入队
if (b->right) {
q.push(b->right);
}
}
}
自己定义链表结构体实现删除倒数第N个链表j节点
//删除倒数第N个链表j节点自己写
// head->next=new Listnode();这样是不行的,因为next是空节点,没有资格进行操作,因为没有val
#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){}
};
ListNode* DeleteNode(ListNode* head,int n); //函数声明
int main(){
cout<<"Please enter the length of the list: ";
int M; cin>>M;
vector<int>nums(M);
ListNode* head=new ListNode();
ListNode* temp=head;
if(M==0){
cout<<"nullptr";
return 0;
}
for(int i=0;i<M;i++){
cin>>nums[i];
temp->next=new ListNode(nums[i]); //反正注意把,只有new的元素可以对next进行操作,操作也是给new!! 除非索引到已经建立的链表就Listnode*temp=head;
temp=temp->next;
temp->next=nullptr;//稳妥起见
}
head=head->next;
//调用函数
cout<<"Please delete the last n node: ";
int n; cin>>n;
ListNode* Head=DeleteNode(head,n);
if(Head==nullptr)
cout<<"This is nullptr";
while(Head!=nullptr){
cout<<Head->val<<" ";
Head=Head->next;
}
return 0;
}
///leetcode函数
ListNode* DeleteNode(ListNode* head,int n){
if(head==nullptr)
return head;
ListNode* dummy = new ListNode(0);
dummy->next=head;
ListNode* cur = dummy;
int length=0;
while(head){
length++;
head=head->next;
}
for (int i = 1; i < length - n + 1; ++i) {
cur = cur->next;
}
cur->next = cur->next->next;
ListNode* ans = dummy->next;
delete dummy;
return ans;
}
自己定义链表结构体实现链表反转
//自己定义结构体实现反转链表
#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:
ListNode* reverseList(ListNode* head){
ListNode* pre=nullptr;
ListNode*curr=head;
while(curr){
ListNode* next=curr->next;
curr->next=pre;
pre=curr;
curr=next;
}
return pre;
}
};
int main(){
int M=5;
vector<int>nums(5);
ListNode* dump=new ListNode();
ListNode* head=dump;
for(int i=0;i<5;i++){
cin>>nums[i];
head->next=new ListNode(nums[i]);
head=head->next;
}
head->next=nullptr;
head=dump->next;
Solution b;
ListNode* res=b.reverseList(head);
for(int i=0;i<M;i++){
cout<<res->val<<' ';
res=res->next;
}
return 0;
}
自己定义链表结构体实现环形链表
#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){
set.insert(head);
if(set.count(head))
return true;
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);
}
自己定义链表结构体实现链表相交查找
//自己定义结构体实现链表相交
#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:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
if (headA == nullptr || headB == nullptr) {
return nullptr;
}
ListNode *pA = headA, *pB = headB;
while (pA != pB) {
pA = pA == nullptr ? headB : pA->next;
pB = pB == nullptr ? headA : pB->next;
}
return pA;
}
};
int main(){
ListNode* headA=new ListNode(1);
ListNode* headB=new ListNode(4);
ListNode* t1=headA;
ListNode* t2=headB;
for(int i=2;i<=5;i++)
{
t1->next=new ListNode(i);
t1=t1->next;
t1->next=nullptr;
}
//1 2 3 4 5-- 4 2 3 4 5
t1=headA;
t1=t1->next;
t2->next=t1;
//输出输入节点
t1=headA;
while(t1)
{
cout<<t1->val<<' ';
t1=t1->next;
}
cout<<endl;
Solution p;
ListNode* res=p.getIntersectionNode(headA,headB);
while(res)
{
cout<<res->val<<' ';
res=res->next;
}
}
组中超过一半的元素-- 哈希表,排序,摩尔投票
class Solution {
public:
int majorityElement(vector<int>& nums) {
int candidate = -1;
int count = 0;
for (int num : nums) {
if (num == candidate)
++count;
else if (--count < 0) {
candidate = num;
count = 1;
}
}
return candidate;
}
};
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int, int> counts;
int majority = 0, cnt = 0;
for (int num: nums) {
++counts[num];
if (counts[num] > cnt) {
majority = num;
cnt = counts[num];
}
}
return majority;
}
};
返回两个数组的中位数,2方法
#include<bits/stdc++.h>
using namespace std;
int main(){
int m,n; cin>>m>>n;
int a[m]={0};
int b[n]={0};
for(int i=0;i<m;i++) cin>>a[i];
for(int i=0;i<n;i++) cin>>b[i];
//
int mid=(m+n-1)/2; //奇数没问题正好是,偶数是左侧一个还要加
int len=m+n;
int sum[m+n];
int i=0,j=0,index=0;
while(i<m && j<n)
{
if(a[i]<=b[j]) sum[index++]=a[i++];
else sum[index++]=b[j++];
}
for(;i<m;) sum[index++]=a[i++];
for(;j<n;) sum[index++]=b[j++];
if(len%2==0) cout<<(sum[mid]+sum[mid+1])/2;
if(len%2==1) cout<<sum[mid];
}
方法二
#include<bits/stdc++.h>
using namespace std;
int main(){
int m,n; cin>>m>>n;
int a[m]={0};
int b[n]={0};
for(int i=0;i<m;i++) cin>>a[i];
for(int i=0;i<n;i++) cin>>b[i];
int mid=(m+n-1)/2; // 中位数左侧的个数 5 左侧2个 4左侧1个;
int len=m+n;
int i=0,j=0,index=0;
int ans=0;
//降低空间复杂度为o(1) 用双指针的方式 走完这个数
while(i<m || j<n)
{
if(i==m)
{
ans=b[j++];
index++;
}
else if(j==n)
{
ans=a[i++];
index++;
}
else if(a[i]<=b[j])
{
ans=a[i++];
index++;
}
else if(a[i]>b[j]){
ans=b[j++];
index++;
}
if(index==mid+1)
break;
}
int ans2=0;
if(i<m && j<n)
ans2=a[i]<=a[j] ? a[i]:b[j];
if(i==m) ans2=b[j];
if(j==n) ans2=a[i];
if(len%2==0)
cout<<(ans+ans2)/2;
if(len%2==1)
cout<<ans;
}
请你计算并返回可以凑成总金额的硬币组合数。–无限个
//请你计算并返回可以凑成总金额的硬币组合数。--无限个
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount + 1);
dp[0] = 1;
for (int& coin : coins) { //完全背包之组合问题,组合必须是物品-容量;然后也是顺序走的容量。
for (int i = coin; i <= amount; i++) {
dp[i] += dp[i - coin];
}
}
return dp[amount];
}
};
零钱兑换I–计算并返回可以凑成总金额所需的 最少的硬币个数 。无限个
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int Max = amount + 1;
vector<int> dp(amount + 1, Max);
dp[0] = 0; //因为第一列容量定义了,所以就是容量从1开始
for (int i = 1; i <= amount; ++i) { //完全背包,顺着走,但是物品-容量也可以变成;容量-物品都可以换。
for (int j = 0; j < (int)coins.size(); ++j) {
if (coins[j] <= i) {
dp[i] = min(dp[i], dp[i - coins[j]] + 1); //最少的个数,就是某个容量下装不同重量的最优.第二次背包容量可以继续装所以是完全顺
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
};
01背包~~~
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
string s1,s2;
string temp;
vector<int>w,v;
cin>>n;
cin.get();
getline(cin,s1);
getline(cin,s2);
stringstream ss1;
ss1<<s1;
stringstream ss2;
ss2<<s2;
while(getline(ss1,temp,',')){
w.push_back(stoi(temp));
}
while(getline(ss2,temp,',')){
v.push_back(stoi(temp));
}
// 结束初始化 进行背包问题
int maxn=0;
vector<int>dp(n+1,0) ;
dp[0]=0; //这个可以不用写
//结束初始化进入循环
for(int i=0; i<w.size();i++){ //i从0开始了,因为没有初始化第一行呢!只是初始化了列。
for(int j=n; j>=w[i];j--){ //这个是01背包 因为逆着的
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
cout<<dp[n];
return 0;
}
完全背包~~就是01顺序换了
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
string s1,s2;
string temp;
vector<int>w,v;
cin>>n;
cin.get();
getline(cin,s1);
getline(cin,s2);
stringstream ss1;
ss1<<s1;
stringstream ss2;
ss2<<s2;
while(getline(ss1,temp,',')){
w.push_back(stoi(temp));
}
while(getline(ss2,temp,',')){
v.push_back(stoi(temp));
}
// 结束初始化 进行背包问题
int maxn=0;
vector<vector<int> >dp(w.size(),vector<int>(n+1,0)) ;
for(int j=w[0];j<=n;j++)
dp[0][j]=v[0];
//结束初始化进入循环
for(int i=1; i<w.size();i++){ //一般习惯先遍历物品再遍历背包容量
for(int j=1; j<=n;j++){ //这个是完全背包 因为是顺着的 不是完全背包就逆着走只能用一次
if(j<w[i])
dp[i][j]=dp[i-1][j];
else{
dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);
}
}
}
cout<<dp[w.size()-1][n];
return 0;
}
搜索插入位置,给定target看在排序的原数组中在哪里应该下标,如果找不到就可能是0 或者n安排
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int n = nums.size();
int left = 0, right = n - 1, ans = n;
while (left <= right) {
int mid = ((right - left) >> 1) + left;
if (target <= nums[mid]) { //n安排了,考虑目标值很小的情况ans
ans = mid; //左边界永远不会越线,这边越线会,但是也是right后面的操作了
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
}
};
最接近的三数之和
//最接近的三数之和
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
if(nums.empty() || nums.size() <= 2) return -1;
int res = nums[0] + nums[1] + nums[2];
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size() - 2; ++i)
{
int left = i + 1, right = nums.size() - 1;
while(left < right)
{
int sum = nums[i] + nums[left] + nums[right];
if(abs(sum - target) < abs(res - target)) res = sum;
if(sum == target) return target;
else if(sum < target) ++left;
else if(sum > target) --right;
}
}
return res;
}
};
盛水最多的容器
class Solution {
public:
int maxArea(vector<int>& height) {
int l = 0, r = height.size() - 1;
int ans = 0;
while (l < r) {
int area = min(height[l], height[r]) * (r - l);
ans = max(ans, area);
if (height[l] <= height[r]) {
++l;
}
else {
--r;
}
}
return ans;
}
};
翻转字符串里的单词–用方法
class Solution {
public:
string reverseWords(string s) {
// 反转整个字符串
reverse(s.begin(), s.end());
int n = s.size();
int idx = 0;
for (int start = 0; start < n; ++start) {
if (s[start] != ' ') { //消除空格
// 填一个空白字符然后将idx移动到下一个单词的开头位置
if (idx != 0) s[idx++] = ' '; //对应的idx还是空格
// 循环遍历至单词的末尾
int end = start; //start开始第一个单词了
while (end < n && s[end] != ' ') s[idx++] = s[end++]; //end是因为他最终到了单词的end 然后在空格处 123 1 start=0,end=4;
// 反转整个单词
reverse(s.begin() + idx - (end - start), s.begin() + idx);
// 更新start,去找下一个单词
start = end; //start是空格处了.
}
}
s.erase(s.begin() + idx, s.end()); //idx是超越点 可以支持超越1点.
//输入字符串可以在前面或者后面包含多余的空格,但是翻转后的字符不能包括。
return s;
}
};
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;
}
};
乘积最大的连续子数组
class Solution {
public:
int maxProduct(vector<int>& nums) {
vector <int> maxF(nums), minF(nums);
for (int i = 1; i < nums.size(); ++i) {
maxF[i] = max(maxF[i - 1] * nums[i], max(nums[i], minF[i - 1] * nums[i]));
minF[i] = min(minF[i - 1] * nums[i], min(nums[i], maxF[i - 1] * nums[i]));
}
return *max_element(maxF.begin(), maxF.end());
}
};
打家劫舍II 环形的
//打家劫舍II 环形的
class Solution {
public:
int rob(vector<int>& nums) {
//这个题目和打家劫舍第一题相当于再增加个条件即可
//最蠢的办法就是正常走删除最后一个元素,或者删除第一个元素正常走
int length=nums.size();
if(nums.empty())
return 0;
if(length==1)
return nums[0];
if(length==2)
return max(nums[0],nums[1]);
vector<int>dp1(length-1);
vector<int>dp2(length-1);
dp1[0]=nums[1];dp1[1]=max(nums[1],nums[2]);
for(int i=2;i<length-1;i++){
dp1[i]=max(dp1[i-2]+nums[i+1],dp1[i-1]);
}
dp2[0]=nums[0];dp2[1]=max(nums[0],nums[1]);
for(int i=2;i<length-1;i++){
dp2[i]=max(dp2[i-2]+nums[i],dp2[i-1]);
}
return max(dp1[length-2],dp2[length-2]);
}
};
顺时针打印矩阵
class Solution
{
public:
vector<int> spiralOrder(vector<vector<int>>& matrix)
{
if (matrix.empty()) return {};
vector<int> res;
int l = 0; //左边界
int r = matrix[0].size() - 1; //右边界
int t = 0; //上边界
int b = matrix.size() - 1; //下边界
while (true)
{
//left -> right
for (int i = l; i <= r; i++) res.push_back(matrix[t][i]);
if (++t > b) break;
//top -> bottom
for (int i = t; i <= b; i++) res.push_back(matrix[i][r]);
if (--r < l) break;
//right -> left
for (int i = r; i >= l; i--) res.push_back(matrix[b][i]);
if (--b < t) break;
//bottom -> top
for (int i = b; i >= t; i--) res.push_back(matrix[i][l]);
if (++l > r) break;
}
return res;
}
};
折叠链表
方法1
class Solution {
public:
void reorderList(ListNode *head) {
if (head == nullptr) {
return;
}
vector<ListNode *> vec;
ListNode *node = head;
while (node != nullptr) {
vec.emplace_back(node);
node = node->next;
}
int i = 0, j = vec.size() - 1;
while (i < j) {
vec[i]->next = vec[j];
i++;
vec[j]->next = vec[i];
j--;
}
vec[i]->next = nullptr;
}
};
==方法2 寻找链表中点 + 链表逆序 + 合并链表 中点就是 1 2 3 4 就是2, 1 2 3 4 5 就是3,中点之前的都保留,后面反转,然后按顺序合并。 ==
class Solution {
public:
void reorderList(ListNode* head) {
if (head == nullptr) {
return;
}
ListNode* mid = middleNode(head);
ListNode* l1 = head;
ListNode* l2 = mid->next;
mid->next = nullptr;
l2 = reverseList(l2);
mergeList(l1, l2);
}
ListNode* middleNode(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while (fast->next != nullptr && fast->next->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
ListNode* reverseList(ListNode* head) {
ListNode* prev = nullptr;
ListNode* curr = head;
while (curr != nullptr) {
ListNode* nextTemp = curr->next;
curr->next = prev;
prev = curr;
curr = nextTemp;
}
return prev;
}
void mergeList(ListNode* l1, ListNode* l2) {
//一定要记录,因为后面变了
ListNode* l1_tmp;
ListNode* l2_tmp;
while (l1 != nullptr && l2 != nullptr) {
l1_tmp = l1->next;
l2_tmp = l2->next;
l1->next = l2;
l1 = l1_tmp;
l2->next = l1;
l2 = l2_tmp;
}
}
};
对getline的数字赋值给数组 ,以空格为界限,也可以修改为逗号 都行
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int n = 0;
int a[N];
int main(){
string str;
getline(cin,str);
str+=" ";
int len = str.size();
int now = 0;
for(int i=0;i<len;i++){
if(str[i]==' '){
a[++n] = now;
now = 0;
}else{
now = now*10+str[i]-'0';
}
}
for(int i=1;i<=5;i++)
cout<<a[i]<<' ';
}
二叉树的前序遍历
class Solution {
public:
void preorder(TreeNode *root, vector<int> &res) {
if (root == nullptr) {
return;
}
res.push_back(root->val);
preorder(root->left, res);
preorder(root->right, res);
}
vector<int> preorderTraversal(TreeNode *root) {
vector<int> res;
preorder(root, res);
return res;
}
};
根据字符串出现的频率排序输出
class Solution {
public:
string frequencySort(string s) {
unordered_map<char, int> mp;
int length = s.length();
for (auto &ch : s) {
mp[ch]++;
}
vector<pair<char, int>> vec;
for (auto &it : mp) { //哈希表的 auto 提出来就是pair
vec.emplace_back(it);
}
sort(vec.begin(), vec.end(), [](const pair<char, int> &a, const pair<char, int> &b) {
return a.second > b.second;
});
string ret;
for (auto &[ch, num] : vec) {
for (int i = 0; i < num; i++) {
ret.push_back(ch);
}
}
return ret;
}
};
链表求和
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); // 计算当前的和
auto res = new ListNode(val % 10);
res -> next = addTwoNumbersCore((l1 ? l1 -> next : nullptr), (l2 ? l2 -> next : nullptr), val / 10);
return res;
}
};
不用哈希表求去字符串重abcdab— abcd
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
getline(cin,s);
int size=s.size();
int vis[256]={0};
string s2;
for(int i=0;i<s.size();i++)
{
if(vis[s[i]-'\0']==0)
{
s2.push_back(s[i]);
vis[s[i]-'\0']=1;
}
}
cout<<s2;
return 0;
}
不用哈希表找出第一个不重复的字符
int main()
{
string str;
getline(cin,str);
bool flag=1;
vector<char> a(26,0);
for(int i=0;i<str.size();i++)
a[str[i]-'a']++;
for(int i=0;i<str.size();i++)
if(a[str[i]-'a']==1)
{
cout<<str[i]<<endl;
flag=0;
break;
}
if(flag) cout<<-1;
return 0;
}
带随机指针链表的深拷贝–或者就是链表的深拷贝方法
class Solution {
public:
unordered_map<Node*, Node*> cachedNode;
Node* copyRandomList(Node* head) {
if (head == nullptr) {
return nullptr;
}
if (!cachedNode.count(head)) { //如果没走过,那就进去开辟next,第一行是和结束建立返回
Node* headNew = new Node(head->val);
cachedNode[head] = headNew; //key和value,value存的是新的空间。key存的是
headNew->next = copyRandomList(head->next);
headNew->random = copyRandomList(head->random);
}
return cachedNode[head]; //如果已经走过这个next了,
}
};
链表中每K个一组反转链表,不足K个就不反转
class Solution {
public:
/// 参考翻转pairs,翻转x~x+(k-1)之间的节点, x->next = reverseKGroup(x+k,k)
ListNode* reverse(ListNode *first,ListNode *last)
{
ListNode *pre = nullptr;
while(first!=last)
{
ListNode *temp = first->next;
first->next = pre;
pre = first;
first = temp;
}
return pre;
}
ListNode *reverseKGroup(ListNode *head, int k)
{
if(!head)
return nullptr;
ListNode *node = head;
for(int i=0;i<k;i++)
{
if(!node)
return head;
node = node->next;
}
ListNode *newHead = reverse(head,node);
head->next = reverseKGroup(node,k);
return newHead;
}
};
MySQL建表~
create table sheetone(
id INT NOT NULL AUTO_INCREMENT, //id是自增的 保证程序的正确性,主键ID首先具有唯一性,设置自动增长在前台Insert的时候不需要传入ID的值,数据库自动根据最后一个ID值增加1 保证数据库主键不重复而且调用更为高效。
title VARCHAR(100) NOT NULL, //int类型整数4字节 1个ASCII码字符串一个字节,那能写100个
author VARCHAR(40) NOT NULL,
submission_date DATE,
PRIMARY KEY (id)
);
求最大公约数和最小公倍数
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
// 辗转相除法求最大公约数
// 1.将较大的数放在a上
// 2.辗转相除
int gcd(int a , int b)
{
// 5 3--1 2,4--2
int count=1;
for(int i=b;i>=1;i--){
if(b%i==0 && a%i==0)
{
count=i;
break;
}
}
return count;
}
// 最小公倍数
// 两个数的最小公倍数就是两个数的乘积除最大公约数
int lcm(int a, int b)
{
int gcd_result = gcd(a,b);
return (a*b)/gcd_result;
}
int main(int argc, char** argv) {
int n,m;
cin>>n>>m;
cout<<"最大公约数"<<endl;
cout<<gcd(n,m)<<endl;
cout<<"最小公倍数"<<endl;
cout<<lcm(n,m);
return 0;
}
8. 字符串转换整数 (atoi)
class Solution {
public:
int myAtoi(string str) {
unsigned long len = str.length();
// 去除前导空格
int index = 0;
while (index < len) {
if (str[index] != ' ') {
break;
}
index++;
}
if (index == len) {
return 0;
}
int sign = 1;
// 处理第 1 个非空字符为正负符号,这两个判断需要写在一起
if (str[index] == '+') {
index++;
} else if (str[index] == '-') {
sign = -1;
index++;
}
// 根据题目限制,只能使用 int 类型
int res = 0;
while (index < len) {
char curChar = str[index];
if (curChar < '0' || curChar > '9') {
break;
}
if (res>0 && res > (INT_MAX-(sign * (curChar - '0')))/10) {
return INT_MAX;
}
if (res<0 && res < (INT_MIN-(sign * (curChar - '0')))/10) {
return INT_MIN;
}
res = res * 10 + sign * (curChar - '0');
index++;
}
return res;
}
};
旋转图像–顺时针90°
class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
// C++ 这里的 = 拷贝是值拷贝,会得到一个新的数组
auto matrix_new = matrix;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
matrix_new[j][n - i - 1] = matrix[i][j];
}
}
// 这里也是值拷贝
matrix = matrix_new;
}
};
字母异位词分组–将异位词放到一个组里分别输出
字母异位词分组
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
unordered_map<string, vector<string>> mp;
for (string& str: strs) {
string key = str;
sort(key.begin(), key.end());
mp[key].emplace_back(str); //排序好的key里面存放若干个没有排序的str
}
vector<vector<string>> ans;
for (auto it = mp.begin(); it != mp.end(); ++it) {
ans.emplace_back(it->second); //注意到这种地址形式要->second 指针了 如果是auto it:mp 就是pair it.second就行了
}
return ans;
}
};
93.复原IP地址----3位数,4组,不能0补位开头,.隔开
class Solution {
public:
vector<string>ans;
void backtrace(string& s,int cnt,int index,string& str){
if(cnt==4 || index==s.size() ){
if(cnt==4 && index==s.size())
ans.push_back(str.substr(0,str.size()-1));
return;
}
for(int i=1;i<=3;i++){
if(index+i>s.size()) return;
if(s[index]=='0' && i!=1) return;//0只能允许是长度是1的情况
if(i==3 && s.substr(index,i)>"255") return;
str+=s.substr(index,i); //从index开始长度为i
str.push_back('.');
backtrace(s,cnt+1,index+i,str); //传入的参数是完成的组数,以及接下来要操作的s中的起始坐标
str = str.substr(0,str.size()-i-1);
}
}
vector<string> restoreIpAddresses(string s) {
string str ="";
backtrace(s,0,0,str);
return ans;
}
};
相同的树–给定两个树头节点,判断是否树是否相同
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(!p && !q) return true;
if(!p || !q || p->val != q->val) return false;
//用递归的方式来搜索
return isSameTree(p->left,q->left) && isSameTree(p->right,q->right);
}
};
剑指 Offer II 093. 最长斐波那契数列
//动态规划+哈希表
class Solution {
public:
int lenLongestFibSubseq(vector<int>& arr) {
vector<vector<int>> dp(arr.size(), vector<int>(arr.size()));
unordered_map<int, int> mp;
for (int i = 0; i < arr.size(); ++i) {
mp[arr[i]] = i;
}
int ret = 0;
for (int i = 1; i < arr.size(); ++i) {
for (int j = 0; j < i; ++j) {
int temp = arr[i] - arr[j];
// 存在 k 使得 A[i] = A[j] + A[k] (0 <= k < j < i)
if (mp.count(temp) && mp[temp] < j) {
dp[i][j] = dp[j][mp[temp]] + 1;
}
// 不存在 k 使得 A[i] = A[j] + A[k] (0 <= k < j < i)
else {
dp[i][j] = 2;
}
ret = max(ret, dp[i][j]);
}
}
return ret > 2 ? ret : 0;
}
};