时空复杂度
1、 0 <n< 30
#include <iostream>
using namespace std;
int f(int n){
if(n==1||n==2) return 1;
return f(n-1)+f(n-2);
}
int main(){
int n;
cin>>n;
cout<<f(n);
return 0;
}
2、 0 <n<100000
#include <iostream>
using namespace std;
const int mod =1e6;
int main(){
int n;
cin>>n;
int a=1,b=1,c;
for(int i=3;i<n;i++){
c=a+b;
c%=mod;
a=b;
b=c;
}
cout<<c;
return 0;
}
3、 0<n<10^10
待定
单链表
1、
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
// head表示第一个结点的下标
//e[i]表示数组下标为i的元素的值,注意这里的i并不代表链表的第i个结点,只表示数组的下标
//ne[i]表示数组下标为i的元素的指针
//idx表示已经插入了多少个元素,是新插入元素的下标
int head, e[N], ne[N], idx;
//初始化
void init()
{
head = -1;//一开始没有第一个结点时,把头指针设为-1
idx = 0;//索引值
}
//让x成为链表的第一个结点,即向链表头插入一个数
void add_to_head(int x)
{
e[idx] = x;//把x赋给第idx个元素
ne[idx] = head;//把第idx个元素的指针指向之前的第一个结点
head = idx++;//让之前第一个结点指向这个元素
}
//删除数组中下标为k的结点,即删除插入的第k个数后面的数
void move(int k)
{
ne[k-1] = ne[ne[k-1]];//把本来指向下标k的指针指向k+1,即跳过k
}
//在下标k-1之后添加结点,即在第k个插入的数后插入一个数
void add(int k, int x)
{
e[idx] = x;//数据
ne[idx] = ne[k-1];//让新结点的指针改为之前第k个数的指针
ne[k-1] = idx;//让第k个结点指向新结点
idx++;
}
int main(void)
{
int m,k,x;
char c;
cin>>m;
init();
while(m--)
{
cin>>c;
if(c=='H')
{
cin>>x;
add_to_head(x);
}
else if(c=='I')
{
cin>>k>>x;;
add(k,x);
}
else if(c=='D')
{
cin>>k;
if(k==0)//k等于0时比较特殊,表示删除链表中的第一个结点,而不是删除插入的第一个数
head=ne[head];
else//删除第k个插入的数后面的数
move(k);
}
}
for(int i=head;i>=0;i=ne[i]) // 最后一个元元素的ne[]为-1
cout<<e[i]<<" ";
cout<<"\n";
return 0;
}
2、
由于是单链表,我们不能找到前驱节点,所以我们不能按常规方法将该节点删除。 我们可以换一种思路,将下一个节点的值复制到当前节点,然后将下一个节点删除即可。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
/*ListNode(int x) {
val = x;
next = null;
} */
class Solution {
public:
void deleteNode(ListNode* node) {
ListNode *p=node->next;
node->next=p->next;
node->val=p->val;
delete p;
}
};
C++中的auto关键字是一个类型说明符,通过变量的初始值或者表达式中参与运算的数据类型来推断变量的类型。编程时通常需要把表达式值式赋给变量,这就要求在声明变量时清楚的知道表达式的类型,C++11新标准引入了auto 类型说明符,让编译器去分析表达式的类型。由于,需要编译器推断变量或表达式的类型,所以,auto定义的变量必须初始化。例如:
auto val = 5.2f; //编译器会根据初始化的值来推断val的数据类型为flaot,但要注意如果去掉f则编译器会认为val为double型变量
auto x = y + z; //x初始化为y和z相加的结果,由y和z的数据类型推断x的数据类型
auto num; //但如果在C++中出现这样的语句,会编译报错,提示“类型包含“auto符号”必须具有初始值设定项”
使用auto也能在一条语句中声明多个变量。因为一条语句声明时只能有一种基本数据类型,所以该语句中的所有变量初始基本数据类型必须一样,例如:
auto i = 0, *p = &i; //正确:i是整数、p是整形指针
auto sz = 0, pi = 3, 14; //错误:sz和pi的类型不一致
3、
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<int> printListReversingly(ListNode* head) {
vector<int> res;
while (head) {
res.push_back(head->val);
head = head->next;
}
return vector<int>(res.rbegin(), res.rend());
}
};
双链表
1、
- 在这里0 和1 只是代表头和尾,并不存储数据
- k 指第几个插入的数
- idx 是第几个结点
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int m;
int e[N], l[N], r[N];
int idx;
//! 初始化
void init()
{
l[1] = 0, r[0] = 1;//* 初始化 第一个点的右边是 1 第二个点的左边是 0
idx = 2;//! idx 此时已经用掉两个点了
}
//* 在第 K 个点右边插入一个 X
void add(int k, int x)
{
e[idx] = x;
l[idx] = k;
r[idx] = r[k]; //todo 这边的 k 不加 1 , 输入的时候 k+1 就好
l[r[k]] = idx;
r[k] = idx;
idx++;
}//! 当然在 K 的左边插入一个数 可以再写一个 , 也可以直接调用我们这个函数,在 k 的左边插入一个 数 等价于在 l[k] 的右边插入一个数 add(l[k],x)
//*删除第 k个 点
void remove(int k)
{
r[l[k]] = r[k];
l[r[k]] = l[k];
}
int main(void)
{
ios::sync_with_stdio(false);
cin >> m;
init();
while(m--)
{
string op;
cin >> op;
int k, x;
if(op=="R")
{
cin >> x;
add(l[1], x); //! 0和 1 只是代表 头和尾 所以 最右边插入 只要在 指向 1的 那个点的右边插入就可以了
}
else if(op=="L")//! 同理 最左边插入就是 在指向 0的数的左边插入就可以了 也就是可以直接在 0的 有右边插入
{
cin >> x;
add(0, x);
}
else if(op=="D")
{
cin >> k;
remove(k + 1);
}
else if(op=="IL")
{
cin >> k >> x;
add(l[k + 1], x);
}
else
{
cin >> k >> x;
add(k + 1, x);
}
}
for(int i = r[0]; i != 1; i = r[i]) cout << e[i] << ' ';
return 0;
}
#include <iostream>
using namespace std;
const int N=100000+10;
int m; //m个整数
int e[N],l[N],r[N]; // N是结点,e是数据
int idx; //第几个结点
void init() //初始化
{
l[1]=0;
r[0]=1;
idx =2; // 头结点尾结点已经占据两个结点,不存储数据
}
void add(int k,int x){ //在K右边插入一个x
e[idx]=x;
r[idx]=r[k]; //1
l[idx]=k; //2
l[r[k]]=idx; //3
r[k]=idx; //4
idx++;
}
/*当然在 K的左边插入一个数可以再写一个 ,也可以直接调用我们这个函数,
在 k 的左边插入一个数等价于在 l[k] 的右边插入一个数 add(l[k],x)
*/
void remove(int k){ //删除第k个结点
r[l[k]]=r[k];
l[r[k]]=l[k];
}
int main(){
ios::sync_with_stdio(false);
cin>> m;
init();
while(m--){
string op;
cin >>op;
int k,x;
if(op=="R")
{
cin >> x;
add(l[1],x); //0和 1 只是代表 头和尾 ,所以最右边插入只要在指向1的 那个点的左边插入就可以了
}
else if(op=="L")
{
cin >> x;
add(0,x); //最左边即头结点0的右边
}
else if(op=="D")
{
cin >>k;
remove(k+1); //第一个结点是k=2时
}
else if(op=="IL")
{
cin >> k >> x;
add(l[k+1],x);
}
else
{
cin >> k >> x;
add(k+1,x);
}
}
for(int i=r[0];i!=1;i=r[i])
cout << e[i] << ' ';
return 0;
}