#include <iostream>
#include <cstring>
#include <string>
#include <stdio.h>
#include <unordered_set>
#include <algorithm>
#include <vector>
#include <limits.h>
#include <map>
#include <stack>
#include <queue>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
};
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
// 给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。
class TreeSolution {
public:
void dfs(vector<int>& res, TreeNode* root, int curHeight) {
if (curHeight == res.size()) {
res.push_back(root->val);
} else {
res[curHeight] = max(res[curHeight], root->val);
}
if (root->left) {
dfs(res, root->left, curHeight + 1);
}
if (root->right) {
dfs(res, root->right, curHeight + 1);
}
}
vector<int> largestValues(TreeNode* root) {
if (!root) {
return {};
}
vector<int> res;
dfs(res, root, 0);
return res;
}
};
// 1 一个字符串 text,你需要使用 text 中的字母来拼凑尽可能多的单词 "balloon"(气球)。
// 字符串 text 中的每个字母最多只能被使用一次。请你返回最多可以拼凑出多少个单词 "balloon"。
int bollnsize(string s){
int ret = -1;\
vector<int> con(5);
// string str = "balloon";
for(int i= 0;i<s.size();i++){
if(s[i] == 'b')
con[0]++;
else if (s[i] == 'a')
con[1]++;
else if (s[i] == 'l')
con[2]++;
else if (s[i] == 'o')
con[3]++;
else if (s[i] == 'n')
con[4]++;
}
con[2] = con[2]/2;
con[3] = con[3]/2;
ret = *min_element(con.begin(),con.end());
return ret;
}
// 2 一个整数 n ,返回 和为 n 的完全平方数的最少数量 。
// 完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
int numSquares(int n) {
vector<int> f(n + 1);
for (int i = 1; i <= n; i++) {//遍历背包
int minn = INT_MAX;
for (int j = 1; j * j <= i; j++) {//遍历物品
minn = min(minn, f[i - j * j]);
}
f[i] = minn + 1;
}
return f[n];
}
// 3 现在两个字符串数组待查表 queries 和词汇表 words 。对于每次查询 queries[i] ,需统计 words 中满足 f(queries[i]) < f(W) 的 词的数目 ,W 表示词汇表 words 中的每个词。
//请你返回一个整数数组 answer 作为答案,其中每个 answer[i] 是第 i 次查询的结果。
int f(string s)
{
sort(s.begin(),s.end());//对字符串进行排序
int count=1;
for(int i=1;i<s.size();i++)
{
if(s[i]==s[i-1])//查找最小字母出现的次数
count++;
else
break;
}
return count;
}
vector<int> numSmallerByFrequency(vector<string>& queries, vector<string>& words) {
vector<int> ans;
vector<int> count(12, 0);//初始化12个长度为0的字符数组
for (int i = 0; i < words.size(); i++)//计算词汇表中每个字符串相同最小次数的个数
count[f(words[i])]++;
for (int i = 9; i >= 0; i--)
count[i] += count[i +1];
for (int i = 0; i < queries.size(); i++)
ans.push_back(count[f(queries[i])+1]);
return ans;
}
// 4 一个链表的头节点 head,请你编写代码,反复删去链表中由 总和 值为 0 的连续节点组成的序列,直到不存在这样的序列为止。
// 删除完毕后,请你返回最终结果链表的头节点。
ListNode *createByTail()
{
ListNode *head;
ListNode *p1,*p2;
int n=0,num;
int len;
cin>>len;
head=NULL;
while(n<len && cin>>num)
{
p1=new ListNode(num);
n=n+1;
if(n==1)
head=p1;
else
p2->next=p1;
p2=p1;
}
return head;
}
void displayLink(ListNode *head)
{
ListNode *p;
p=head;
cout<<"head-->";
while(p!= NULL)
{
cout<<p->val<<"-->";
p=p->next;
}
cout<<"tail\n";
}
class Solution {
public:
ListNode* removeZeroSumSublists(ListNode* head) {
map <int,ListNode*> map;
ListNode* dummy = new ListNode(0);
dummy->next = head;
int sum = 0;
//计算各个节点的前缀和存入map,若有相同前缀和存入后一个位置
for (ListNode* d = dummy; d != NULL; d = d->next) {
sum += d->val;
map[sum] = d;
}
// 第二遍遍历 若当前节点处sum在下一处出现了则表明两结点之间所有节点和为0 直接删除区间所有节点(从前面的一个sum处的节点指向后面的另一个sum处的节点的next)
sum = 0;
for (ListNode* d = dummy; d != NULL; d = d->next) {
sum += d->val;
if(map.find(sum) != map.end())
d->next = map[sum]->next;
}
return dummy->next;
}
//方法二
struct ListNode* removeZeroSumSublists2(struct ListNode* head)
{
struct ListNode* p = (struct ListNode*)malloc(sizeof(ListNode));
p->next = head;
p->val = 0;
struct ListNode* record1 = NULL;
struct ListNode* record2 = p;
int sum = 0;
while (record2)
{
sum = 0;
record1 = record2->next;//第一次就是head
while (record1)
{
sum += record1->val;
if (sum == 0)
{
record2->next = record1->next;//record2开始到record1的位置和为0
}
record1 = record1->next;
}
record2 = record2->next;
}
return p->next;
}
};
//获取字符数组中相同元素的个数
int setsize(int* so,int size){
unordered_set<int> iset;
for(int i=0;i<size;i++){
iset.insert(so[i]);
cout<<"insert:"<<so[i]<<endl;
}
return iset.size();
}
// 5 如果其中某一张多米诺骨牌可以通过旋转 0 度或 180 度得到另一张多米诺骨牌,我们就认为这两张牌是等价的。
// 形式上,dominoes[i] = [a, b] 和 dominoes[j] = [c, d] 等价的前提是 a==c 且 b==d,或是 a==d 且 b==c。(
// 在 0 <= i < j < dominoes.length 的前提下,找出满足 dominoes[i] 和 dominoes[j] 等价的骨牌对 (i, j) 的数量。
int numEquivDominoPairs(vector<vector<int>>& dominoes) {
vector<int> num(100);
int ret = 0;
for (auto& it : dominoes) {
//a+b == c+d 这种逻辑应该也符合
int val = it[0] < it[1] ? it[0] * 10 + it[1] : it[1] * 10 + it[0]; //计算这两张牌总和 并将和相等的数记录每多一个该值+1
ret += num[val];//总共多少相同的
num[val]++;//有相同值
}
return ret;
}
// 6 一个正整数数组 arr,考虑所有满足以下条件的二叉树:
// 每个节点都有 0 个或是 2 个子节点。
// 数组 arr 中的值与树的中序遍历中每个叶节点的值一一对应。(知识回顾:如果一个节点有 0 个子节点,那么该节点为叶节点。)
// 每个非叶节点的值等于其左子树和右子树中叶节点的最大值的乘积。
// 在所有这样的二叉树中,返回每个非叶节点的值的最小可能总和。这个和的值是一个 32 位整数。
// 这个题实际上是将数组中相邻的数两两合并,计算他们的乘积之和,求最小的乘积之和。合并相邻的两个数之后得到的是较大的一个数,显然先将两个更小的数合并得到的乘积之和 res 更小
// 这样就可以利用单调栈来完成,维护一个单调递减的栈,栈中存放具体的元素值。
// 如果当前遍历到的元素比栈顶元素大,则需要判断当前元素与栈顶第二个元素的大小,优先选择更小的元素与栈顶元素进行合并。
// 如果遇到递增的情况,直接进行合并
int mctFromLeafValues(vector<int>& arr) {
int res = 0;
stack<int> s;
s.push(INT_MAX);//初始化栈压入最大int数
// int n = arr.size();
for (auto& a : arr) {
while (s.top() <= a) {//单调递减栈
cout<<"val:"<<a<<" top:"<<s.top()<<endl;
int temp = s.top();
s.pop();//弹出已知栈顶小的元素
res += temp * min(s.top(), a);//合并两个小的元素
}
s.push(a);
}
//排序后栈大小大于2 需要将递减的栈进行合并运算
while (s.size() > 2) {
int temp = s.top();
s.pop();
res += temp * s.top();
}
return res;
}
// 7 斐波那契序列 Tn 定义如下:
// T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2
// 给你整数 n,请返回第 n 个泰波那契数 Tn 的值。
int tribonacci(int n) {
vector<int> T(40);
T[0] = 0; T[1] = 1; T[2] = 1;
for(int i = 3;i <= n;i++){//直接从第三个往后计算
T[i] = T[i-1] +T[i-2] + T[i-3];
}
return T[n];
}
// 8 给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
// 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
// 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
// 两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
int longestCommonSubsequence(string text1, string text2) {
int len = 0;
int jflag = 0;
string strmin,strmax;
if(text1.size() > text2.size()){
strmax = text1; strmin = text2;}
else{strmin = text1; strmax = text2;}
for(int i= 0;i<strmin.size();i++){
for(int j = jflag;j<strmax.size();j++){
if(text1[i] == text2[j]){//若匹配到相同字符
len++;//相同字符长度++
jflag = j; //被匹配字符下标记录 第二字符从这开始继续向后匹配
}
}
}
return len;
}
// 9 给定一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于 k 。返回这一子串的长度。
int longestSubstring(string s, int k) {
if (k <= 1) return s.size();
if (s.empty() || s.size() < k) return 0;
vector<int> hash(128, 0);
for (char c : s) ++hash[c]; //将相同字符计数填充到列表中
int i = 0;
while (i < s.size() && hash[s[i]] >= k) ++i; //连续字符大于k的个数
if (i == s.size()) return s.size();//字符串由一个字符组成
int l = longestSubstring(s.substr(0, i), k);
while (i < s.size() && hash[s[i]] < k) ++i;//连续字符小于k的个数
int r = longestSubstring(s.substr(i), k);
return max(l, r);
}
// 10 给定一个正整数 n ,你可以做如下操作:(整数替换 递归)
// 如果 n 是偶数,则用 n / 2替换 n 。
// 如果 n 是奇数,则可以用 n + 1或n - 1替换 n 。
// 返回 n 变为 1 所需的 最小替换次数 。
int integerReplacement(int n) {
int cnt = 0;
if(n<=1) return cnt;
if(n%2 == 0){
return 1+integerReplacement(n/2);
}
else{
return 1+min(integerReplacement(n+1),integerReplacement(n-1));
}
}
// 11 给定一个整数数组 asteroids,表示在同一行的小行星。
// 对于数组中的每一个元素,其绝对值表示小行星的大小,正负表示小行星的移动方向(正表示向右移动,负表示向左移动)。每一颗小行星以相同的速度移动。
// 找出碰撞后剩下的所有小行星。碰撞规则:两个行星相互碰撞,较小的行星会爆炸。如果两颗行星大小相同,则两颗行星都会爆炸。两颗移动方向相同的行星,永远不会发生碰撞。
vector<int> asteroidCollision(vector<int>& asteroids) {
vector<int> st;
for (auto aster : asteroids) {
bool alive = true;
while (alive && aster < 0 && !st.empty() && st.back() > 0) {//当aster存在且小于0,栈顶元素非空且大于0
alive = st.back() < -aster; // 栈顶元素小于 -aster aster存在
if (st.back() <= -aster) { //栈顶元素小于等于-aster 栈顶小行星爆炸
st.pop_back();//出栈
}
}
if (alive) {//将存在的小行星入栈
st.push_back(aster);
}
}
return st;
}
// 12 请根据每日 气温 列表 temperatures ,重新生成一个列表,要求其对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
class tempdemo
{
public:
//单调栈解法
vector<int> dailyTemperatures1(vector<int>& temperatures) {
int n = temperatures.size();
stack<pair<int, int>> st; //pair记录温度与日期
vector<int> ans(n);
for (int i = 0; i < n; ++i) { //遍历时需要判断此时的温度是否大于栈顶温度
while (!st.empty()) {//循环判断当前元素与已经入栈递减的元素 大小更新栈内数据
auto p = st.top();
if (temperatures[i] <= p.first) { //若小于 则可以直接入栈
break;
} else { //若大于 则出栈后继续比较
ans[p.second] = i - p.second;
st.pop();
}
}
st.push({temperatures[i], i});
}
return ans;
}
//暴力遍历
vector<int> dailyTemperatures2(vector<int>& temperatures) {
int size = temperatures.size();
vector<int> tempupday(size,0);//初始化队列为0
for(int i = 0;i<size;i++){
for(int j = i+1;j<size; j++ ){
if(temperatures[j] > temperatures[i]){ //找到后一个大于当前温度的位置,则位置相减得到位置差 没有则默认为0
tempupday[i] = j-i;
break;
}
}
}
return tempupday;
}
};
// 13 给定一个整数数据流和一个窗口大小,根据该滑动窗口的大小,计算滑动窗口里所有数字的平均值。
// 实现 MovingAverage 类:
// MovingAverage(int size) 用窗口大小 size 初始化对象。
// double next(int val) 成员函数 next 每次调用的时候都会往滑动窗口增加一个整数,请计算并返回数据流中最后 size 个值的移动平均值,即滑动窗口里所有数字的平均值。
class MovingAverage {
public:
MovingAverage(int size) {
max_size=size;
sum=0;
}
double next(int val) {
if(myqu.size()==max_size){ //如果容器大小超过size个值,则将前面的值给舍弃掉
sum-=myqu.front(); //总和也减去舍弃的值
myqu.pop();
}
sum+=val;
myqu.push(val); //添加元素
return sum/myqu.size();
}
public:
int max_size;
double sum;
queue<int> myqu; //维护一个容器,最多保留size个值,
};
// 14 给你一个由 n 个元素组成的整数数组 nums 和一个整数 k 。
// 请你找出平均数最大且 长度为 k 的连续子数组,并输出该最大平均数。
double findMaxAverage(vector<int>& nums, int k) {
queue<int> sum;//k个元素的窗口
vector<int> vct;//窗口元素和列表
int total = 0;
for(int i = 0;i<=nums.size(); i++){
if(sum.size() == k){
vct.push_back(total);//四元素队列的和
cout<<"total:"<<total<<endl;
total -= sum.front();//减去队列中第一个
sum.pop();//弹出第一个
}
sum.push(nums[i]);
total += nums[i];
}
auto average = max_element(vct.begin(),vct.end());
cout<<"average:"<<*average<<endl;
return (double)*average/k;
}
// 15 一个有名的按摩师会收到源源不断的预约请求,每个预约都可以选择接或不接。在每次预约服务之间要有休息时间,因此她不能接受相邻的预约(有可能隔多个)。
// 给定一个预约请求序列,替按摩师找到最优的预约集合(总预约时间最长),返回总的分钟数。
int massage(vector<int>& nums) {
int n = (int)nums.size();
if (!n) {
return 0;
}
int dp0 = 0, dp1 = nums[0];
// 定义 dp[i][0] 表示考虑前 i 个预约,第 i个预约不接的最长预约时间,dp[i][1] 表示考虑前 i个预约,第 i个预约接的最长预约时间。
for (int i = 1; i < n; ++i){
int tdp0 = max(dp0, dp1); // 计算 dp[i][0]
int tdp1 = dp0 + nums[i]; // 计算 dp[i][1]
dp0 = tdp0; // 用 dp[i][0] 更新 dp_0
dp1 = tdp1; // 用 dp[i][1] 更新 dp_1
}
return max(dp0, dp1);
}
// (15相同)你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,
// 如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
// 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
int rob(vector<int>& nums) {
if (nums.size() == 0) {
return 0;
}
// 子问题:
// f(k) = 偷 [0..k) 房间中的最大金额
// f(0) = 0
// f(1) = nums[0]
// f(k) = max{ rob(k-1), nums[k-1] + rob(k-2) }
int N = nums.size();
vector<int> dp(N+1, 0);
dp[0] = 0;
dp[1] = nums[0];
for (int k = 2; k <= N; k++) { //比较出+第k-1个元素和与前面最大元素和 大的放入数组类 计算下一个
dp[k] = max(dp[k-1], nums[k-1] + dp[k-2]);
}
return dp[N];
}
int main(){
int ret = -1;
/*
int num[] = {1,3,4,2,1,4,4,0};
int sizen = sizeof(num)/sizeof(num[0]);
cout<<"count:"<<sizen<<endl;
ret = setsize(num,sizen);
cout<<"无重复数字个数:"<<ret<<endl;
*/
/********* 1 **********/
// string str = "loonbalxballpoon";
// cout<<"balloon count:"<<bollnsize(str)<<endl;
// cout<<"完全平方数min count:"<<numSquares(13)<<endl;
/********* 3 **********/
/*
vector<int> res;
string str = "sbbceeed";
vector<string> queries = {"bbb","cc"};
vector<string> word = {"a","aa","aaa","aaaa"};
res = numSmallerByFrequency(queries,word);
for(int i= 0 ; i< res.size();i++){
cout<<res[i]<<" ";
}
cout<<endl;
*/
/********* 4 **********/
// ListNode* head = createByTail();
// ListNode* p = NULL;
// p=Solution().removeZeroSumSublists(head);
// displayLink(p);
/********* 5 **********/
// vector<vector<int>> domi = {{1,2},{2,1},{1,2}};
// vector<int> a(1,2);
// vector<int> b(2,1);
// ret = numEquivDominoPairs(domi);
// cout<<"card common count:"<<ret<<endl;
/********* 6 **********/
// vector<int> arr = {6,2,3,4};
// ret = mctFromLeafValues(arr);
// cout<<"tree val:"<<ret<<endl;
/********* 7 **********/
// ret = tribonacci(2);
// cout<<"tribonacci val:"<<ret<<endl;
/********* 8 **********/
// string a = "bsbininm";
// string b = "jmjkbkjkv";
// ret = longestCommonSubsequence(b,a);
// cout<<"longcommonstr count:"<<ret<<endl;
/********* 9 **********/
// string str = "aabbbcde";
// int k = 3;
// ret = longestSubstring(str,k);
// cout<<"longestSubstring count:"<<ret<<endl;
/********* 10 **********/
// int var = 7;
// ret = integerReplacement(var);
// cout<<"integerReplacement count:"<<ret<<endl;
/********* 11 **********/
// vector<int> ordis = {6,-2,-1,1,2};
// vector<int> res;
// res = asteroidCollision(ordis);
// cout<<"asteroidCollision :";
// for(int i = 0;i<res.size();i++){
// cout<<res[i]<<",";
// }
// cout<<endl;
/********* 12 **********/
// vector<int> ordis ={73,74,75,71,69,72,76,73};
// vector<int> res;
// tempdemo demo;
// res = demo.dailyTemperatures1(ordis);
// cout<<"dailyTemperatures :";
// for(int i = 0;i<res.size();i++){
// cout<<res[i]<<",";
// }
// cout<<endl;
/********* 13 **********/
// MovingAverage mov(3);
// double average = 0;
// average = mov.next(4);
// average = mov.next(2);
// average = mov.next(6);
// cout<<"MovingAverage:"<<average<<endl;
/********* 14 **********/
// vector<int> a{1,12,-5,-6,50,3,30};
// int k = 4;
// double average = 0;
// average = findMaxAverage(a,k);
// cout<<"findMaxAverage:"<<average<<endl;
/********* 15 **********/
vector<int> a{2,1,4,5,3,1,1,3};
ret = rob(a);
// ret = massage(b);
cout<<"MaxSeverTime:"<<ret<<endl;
return 0;
}
c++力扣算法题
最新推荐文章于 2024-03-08 22:26:59 发布