# 贼全面的计算机考研数据结构算法题集合（408+自命题均可）

46 篇文章 14 订阅

## Code

### 数组

#### 合并排序的数组

void merge(int* A, int ASize, int m, int* B, int BSize, int n){
if(ASize == 0) return;
int * c = (int *)malloc(sizeof(int )*ASize);
int num = 0,j,k;
for(int i = 0;i < ASize;i++)
c[i] = 0;
for(j = 0,k = 0;j < m && k < n;num++)
{
if(A[j] <= B[k])
c[num] = A[j++];
else
c[num] = B[k++];
}
while(j < m) c[num++] = A[j++];
while(k < n) c[num++] = B[k++];
for(int i = 0;i < ASize;i++)
A[i] = c[i];
return;
}


#### 约瑟夫环问题——高效解法

0,1,···,n-1这n个数字排成一个圆圈，从数字0开始，每次从这个圆圈里删除第m个数字（删除后从下一个数字开始计数）。求出这个圆圈里剩下的最后一个数字。


int f(int n, int m) {
if (n == 1) {
return 0;
}
int x = f(n - 1, m);
return (m + x) % n;
}
int lastRemaining(int n, int m) {
return f(n, m);
}


k 神题解

### 栈

#### 栈实现队列

• void push(int x) 将元素 x 推到队列的末尾
• int pop() 从队列的开头移除并返回元素
• int peek() 返回队列开头的元素
• boolean empty() 如果队列为空，返回 true ；否则，返回 false

typedef struct {
int *in_stack;
int *out_stack;
int top_in;
int top_out;
int size;
} MyQueue;

MyQueue* myQueueCreate() {
MyQueue* m = (MyQueue *)malloc(sizeof(MyQueue)*1);
m->in_stack = (int*)malloc(sizeof(int)*110);
m->out_stack = (int*)malloc(sizeof(int)*110);
m->top_in = -1;
m->top_out = -1;
m->size = 0;
return m;
}

void myQueuePush(MyQueue* obj, int x) {
obj->in_stack[++(obj->top_in)] = x;
obj->size++;
return ;
}

int myQueuePop(MyQueue* obj) {
if(obj->top_out == -1)
{
while(obj->top_in >= 0)
obj->out_stack[++(obj->top_out)] = obj->in_stack[(obj->top_in)--];
}
(obj->size)--;
return obj->out_stack[(obj->top_out)--];
}

int myQueuePeek(MyQueue* obj) {
if(obj->top_out == -1)
{
while(obj->top_in >= 0)
obj->out_stack[++(obj->top_out)] = obj->in_stack[(obj->top_in)--];
}
return obj->out_stack[obj->top_out];
}

bool myQueueEmpty(MyQueue* obj) {
if(obj->size == 0)
return true;
else
return false;
}

void myQueueFree(MyQueue* obj) {
free(obj->in_stack);
free(obj->out_stack);
obj->top_out = -1;
obj->top_in = -1;
obj->size = 0;
return ;
}
/**
* Your MyQueue struct will be instantiated and called as such:
* MyQueue* obj = myQueueCreate();
* myQueuePush(obj, x);
* int param_2 = myQueuePop(obj);
* int param_3 = myQueuePeek(obj);
* bool param_4 = myQueueEmpty(obj);
* myQueueFree(obj);
*/


#### 最小栈

• push(x) —— 将元素 x 推入栈中。
• pop() —— 删除栈顶的元素。
• top() —— 获取栈顶元素。
• getMin() —— 检索栈中的最小元素。
typedef struct {
int *arr;
int top;
int size;//xieshangzaishuo
int min_num;
int *brr;
} MinStack;

MinStack* minStackCreate() {
MinStack* m = (MinStack *)malloc(sizeof(MinStack)*1);
m->arr = (int *)malloc(sizeof(int)*101000);
m->brr = (int *)malloc(sizeof(int)*101000);
m->top = -1;
m->size = 0;
m->min_num = 2147483647;
return m;
}

void minStackPush(MinStack* obj, int val) {
obj->arr[++(obj->top)] = val;
(obj->size)++;
if(val < (obj->min_num))
{
obj->min_num = val;
// obj->brr[(obj->top)] = obj->min_num;
}
obj->brr[(obj->top)] = obj->min_num;
// else
// obj->brr[(obj->top)] =
}

int minStackTop(MinStack* obj) {
return obj->arr[(obj->top)];
}

void minStackPop(MinStack* obj) {
(obj->size)-= 1;
(obj->top)--;
// 最小的弹出去之后 记得更新 min_num
if(obj->size == 0)
obj->min_num = 2147483647;
else
obj->min_num = obj->brr[(obj->top)];
}

int minStackGetMin(MinStack* obj) {
return obj->brr[obj->top];
}

void minStackFree(MinStack* obj) {
free(obj->arr);
free(obj->brr);
obj->size = 0;
obj->top = -1;
obj->min_num = 0;
}


#### 逆波兰表达式求值

• 整数除法只保留整数部分。
• 给定逆波兰表达式总是有效的。换句话说，表达式总会得出有效数值且不存在除数为 0 的情况。
/*

*/
int evalRPN(char ** tokens, int tokensSize){
int *stack = (int *)calloc(tokensSize,sizeof(int));
int top = 0;
int a,b;
for(int i = 0;i < tokensSize;i++)
{
char *c = tokens[i];
if(strlen(c) == 1 && c[0] >= 42 && c[0] <= 47 )
{
b = stack[top-1];
a = stack[top-2];
top = top- 2;
switch(c[0])
{
case '+':
stack[top++] = a+b;
break;
case '-':
stack[top++] = a-b;
break;
case '*':
stack[top++] = a*b;
break;
case '/':
stack[top++] = a/b;
break;
}
}
else
stack[top++] = atoi(c);
}
return stack[--top];
}


### 队列

#### 设计循环队列

• MyCircularQueue(k): 构造器，设置队列长度为 k 。
• Front: 从队首获取元素。如果队列为空，返回 -1 。
• Rear: 获取队尾元素。如果队列为空，返回 -1 。
• enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
• deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
• isEmpty(): 检查循环队列是否为空。
• isFull(): 检查循环队列是否已满。
typedef struct {
int k;
int *queue;
int length;
int front,rear;
} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue *q = (MyCircularQueue *)calloc(1,sizeof(MyCircularQueue));
q->queue = (int *)calloc(k,sizeof(int));
q->k = k;
q->front = -1;
q->rear = -1;
q->length = 0;
return q;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(obj->length == obj->k)
return false;

if(obj->front == -1 && obj->rear == -1)
{
obj->front = 0;
obj->rear = 0;
}
obj->queue[obj->rear] = value;
obj->rear = (obj->rear+1)%obj->k;
obj->length++;
return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(obj->length == 0)
return false;

obj->front = (obj->front+1)%obj->k;
obj->length--;
return true;
}

int myCircularQueueFront(MyCircularQueue* obj) {
if(obj->length == 0)
return -1;

return obj->queue[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) {
if(obj->length == 0)
return -1;

if(obj->rear - 1 == -1)
return obj->queue[obj->rear-1+obj->k];

return obj->queue[obj->rear-1];
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
if(obj->length != 0)
return false;

return true;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
if(obj->length != obj->k)
return false;

return true;
}

void myCircularQueueFree(MyCircularQueue* obj) {
obj->front = -1;
obj->rear = -1;
obj->length = 0;
if(obj->queue != NULL)
{
free(obj->queue);
obj->queue = NULL;
}
if (obj != NULL) {
free(obj);
obj = NULL;
}
}

/**
* Your MyCircularQueue struct will be instantiated and called as such:
* MyCircularQueue* obj = myCircularQueueCreate(k);
* bool param_1 = myCircularQueueEnQueue(obj, value);
* bool param_2 = myCircularQueueDeQueue(obj);
* int param_3 = myCircularQueueFront(obj);
* int param_4 = myCircularQueueRear(obj);
* bool param_5 = myCircularQueueIsEmpty(obj);
* bool param_6 = myCircularQueueIsFull(obj);
* myCircularQueueFree(obj);
*/


### 链表

#### 删除链表节点

struct ListNode* deleteNode(struct ListNode* head, int val){
int num = val;
struct ListNode* s = (struct ListNode*)malloc(sizeof(struct ListNode)*1);
struct ListNode*p,*q;
p = s;
while(p->next!=NULL)
{
if(p->next->val == num)
{
q = p->next;
p->next = q->next;
break;
}
p = p->next;
}
return s->next;
}


#### 删除链表中间节点

• 对于 n = 1、2、3、4 和 5 的情况，中间节点的下标分别是 0、1、1、2 和 2 。
// 一波优雅的快慢指针
return NULL;
struct ListNode* l = (struct ListNode*)calloc(1,sizeof(struct ListNode));
struct ListNode*p,*q;
p = l;
while(q != NULL && q->next != NULL)
{
q = q->next->next;
p = p->next;
}
// q = p->next;
p->next = p->next->next;
return l->next;
}


#### 删除链表的倒数第n个节点

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode *p,*q;
struct ListNode *l = (struct ListNode*)malloc(sizeof(struct ListNode)*1);
l->next = NULL;
p = q = l; //p->next指向第n-1结点 q->next指向后边的结点
while(n--)
{
p = p->next;
}
while(p->next != NULL)
{
p = p->next;
q = q->next;
}
p = q->next;
q->next = q->next->next;
free(p);
return l->next;
}


#### 删除链表中的重复元素

struct ListNode* deleteDuplicates(struct ListNode* head){
return NULL;
struct ListNode* s,* p,* pre,* q;
struct ListNode* l = (struct ListNode *)malloc(sizeof(struct ListNode)*1);
pre = l;
// int x = pre->next->val;
while(p != NULL && p->next != NULL)
{
if(p->val == s->val)
{
while(p->val == s->val && s->next != NULL)
{
q = s;
s = s->next;
p->next = s;
free(q);
}
if(s->val == p->val && s->next == NULL)
{
p = NULL;
pre->next = p;
break;
}
q = p;
pre->next = q->next;
free(q);
// pre = pre->next;
p = pre->next;
s = p->next;
}
else
{
pre = p;
p = s;
s = s->next;
}
}
return l->next;
}


#### 相交链表

// 觉得优雅的不太优雅代码
struct ListNode *s = (struct ListNode *)malloc(sizeof(struct ListNode)*1);
struct ListNode * a, * b,* a_x,* b_x;
int len = 0;
int flag = 1;
while(a != NULL && b != NULL)
{
a = a->next;
b = b->next;
}
while(a!= NULL)
{
len++;
flag = 1;
a = a->next;
}
while(b!= NULL)
{
len++;
flag = 0;
b = b->next;
}
while(len > 0)
{
if(flag == 0)
b_x  = b_x->next;
else
a_x = a_x->next;
len--;
}
while(a_x != NULL)
{
if(a_x == b_x)
return a_x;
else
{
a_x = a_x -> next;
b_x = b_x -> next;
}
}
return NULL;
}

// 觉得不优雅的优雅代码
return NULL;
}
while (pA != pB) {
pA = pA == NULL ? headB : pA->next;
pB = pB == NULL ? headA : pB->next;
}
return pA;
}


#### 链表中环的入口点

struct ListNode *detectCycle(struct ListNode *head) {
while(1)
{
if(first == NULL || first -> next == NULL)
return NULL;

slow = slow -> next;
first = first -> next -> next;
if(first == slow)
break;
}

int k = 0;
while(first != slow)
{
first = first -> next;
slow = slow -> next;
k++;
}
return slow;
}


#### 反转链表

struct ListNode* reverseList(struct ListNode* head){
struct ListNode* pre;
struct ListNode* a;
struct ListNode* end;
pre = NULL;

while(a != NULL)
{
end = a->next;
a->next = pre;
pre = a;
a = end;
}
return pre;
}


#### 旋转链表

struct ListNode* rotateRight(struct ListNode* head, int k){
return NULL;

struct ListNode* slow,* first;
int len = 0;
while(s!= NULL)
{
s = s->next;
len++;
}
k = k%len;
// printf("%d",k);
if(k == 0)
struct ListNode* lnode = (struct ListNode* )malloc(sizeof(struct ListNode)*1);
slow = first = lnode;
while(k--)
{
first = first->next;
}

while(first->next != NULL)
{
slow = slow->next;
first = first->next;
}
struct ListNode* l;
l = slow->next;
slow->next = NULL;
slow = l;
while(l->next != NULL && l != NULL)
{
l = l->next;
}
return slow;
}


#### 合并两个链表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g4yNwfV8-1657848413468)(images/code/fig1.png)]

struct ListNode* mergeInBetween(struct ListNode* list1, int a, int b, struct ListNode* list2){
struct ListNode* s;
struct ListNode* pre;
struct ListNode* f;
s = list1;
int cha = b - a;
while(--a)
s = s->next;

pre = s;
s = s->next;
while(cha--)
{
f = s;
s = s->next;
free(f);
}
pre -> next = list2;

while(pre -> next != NULL)
pre = pre->next;

pre->next = s->next;
return list1;
}


#### 重排链表

L0 → L1 → … → Ln - 1 → Ln

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

struct ListNode* reverseList(struct ListNode* head) {
while (cur) {
nxt = cur->next;
cur->next = pre->next;
pre->next = cur;
cur = nxt;
}
}

while (fp->next && fp->next->next) {
fp = fp->next->next;
sp = sp->next;
}
struct ListNode *sh = reverseList(sp->next);
sp->next = NULL;
struct ListNode *th = head, *tp = NULL;
while (th && sh) {
tp = sh->next;
sh->next = th->next;
th->next = sh;
th = sh->next;
sh = tp;
}
}


#### 链表排序——插入

struct ListNode* insertionSortList(struct ListNode* head){

struct ListNode *l = (struct ListNode *)malloc(sizeof(struct ListNode));
l->val = 0;
//cur外循环遍历
while (cur != NULL)
{
if(pre->val <= cur->val)
pre = pre->next;
else
{
struct ListNode *move = l;
while(move->next->val <= cur->val)
move = move->next;

pre->next = cur->next;
cur->next = move->next;
move->next = cur;
}
cur = pre->next;
}
return l->next;
}


#### 链表排序——归并

struct ListNode * merge(struct ListNode *m,struct ListNode *n)
{
struct ListNode *d = (struct ListNode *)malloc(sizeof(struct ListNode)*1);
while(m!=NULL && n!=NULL)
{
if(m->val <= n->val)
{
m = m->next;
}
else
{
n = n->next;
}
}
if(m!=NULL)
if(n!=NULL)
return d->next;
}
struct ListNode* mergesort(struct ListNode *low,struct ListNode *mid)
{
if(low == NULL)
return NULL;
if(low -> next == mid)
{
low->next = NULL;
return low;
}
//归并
struct ListNode *s = low;
struct ListNode *f = low;
while(f != mid && f->next != mid)
{
s = s->next;
f = f->next->next;
}
return merge(mergesort(low,s),mergesort(s,mid));
}
}


### 二叉树

#### 中序遍历

// 递归
void inorder(struct TreeNode* root,int returns[],int *returnSize)
{
if(root == NULL)
return;
inorder(root->left,returns,returnSize);
returns[(*returnSize)++] = root->val;
inorder(root->right,returns,returnSize);
}

// 非递归
int* inorderTraversal(struct TreeNode* root, int* returnSize){
*returnSize = 0;
int* returns = (int *)malloc(sizeof(int )*110);
struct TreeNode *s[110];
int top = 0;
struct TreeNode *m = root;
while(m!=NULL || top != 0)
{
if(m)
{
s[top++] = m;
m = m->left;
}
else
{
m = s[--top];
returns[(*returnSize)++] = m->val;
m = m -> right;
}
}
return returns;
}


#### 前序遍历

// 递归
void preorder(struct TreeNode* root,int returns[],int *returnSize)
{
if(root == NULL) return;

returns[*returnSize] = root->val;
(*returnSize)++;
preorder(root->left,returns,returnSize);
preorder(root->right,returns,returnSize);
}

// 非递归
typedef struct stack{
struct TreeNode* data[110];
int top;
}stack;
void push(stack *s,struct TreeNode *x)
{
s->data[(s->top)] = x;
(s->top)++;
}
struct TreeNode *pop(stack *s,struct TreeNode *x)
{
x = s->data[--(s->top)];
return x;
}
void init(stack *s)
{
(s->top) = 0;
}
int empty(stack s)
{
if(s.top == 0)
return 0;
return 1;
}
void visit(struct TreeNode* x,int returns[],int *returnSize)
{
returns[(*returnSize)++] = x->val;
}
int* preorderTraversal(struct TreeNode* root, int* returnSize){
*returnSize = 0;
int* returns = (int *)malloc(sizeof(int)* 110);
struct TreeNode *m;
m = root;
stack s;
init(&s);
while(m != NULL || empty(s)!= 0)
{
if(m)
{
visit(m,returns,returnSize);
push(&s,m);
m = m->left;
}
else
{
m = pop(&s,m);
m = m->right;
}
}
return returns;
}


#### 后序遍历

// 递归
void postorder(struct TreeNode* root,int returns[],int *returnSize)
{
if(root == NULL) return;

postorder(root->left,returns,returnSize);
postorder(root->right,returns,returnSize);
returns[(*returnSize)++] = root->val;
}

// 非递归
int* postorderTraversal(struct TreeNode* root, int* returnSize){
*returnSize = 0;
int *returns = (int *)malloc(sizeof(int)* 110);
struct TreeNode* data[110];
int top = 0;
struct TreeNode* m = root;
struct TreeNode* pre = NULL;
while(m || top != 0)
{
while(m)
{
pre = m;
data[top++] = m;
m = m->left;
}
m = data[--top];
if(m->right != NULL && m->right != pre)
{
data[top++] = m;
m = m->right;
}
else
{
pre = m;
returns[(*returnSize)++] = pre->val;
m = NULL;
}
}
return returns;
}


#### 二叉树的层序遍历

// em 优雅！
// bfs 模板题 一层一层访问
void bfs(struct TreeNode* root,int **returns,int *returnSize,int **returnColumnSizes)
{
int front = 0;
int rear = 0;
struct TreeNode* queue[1010];
queue[rear++] = root;

while(front != rear)
{
int cha = rear - front;
returns[(*returnSize)] = (int *)malloc(sizeof(int)*(cha));
for(int i = 0;i < cha;i++)
{
returns[(*returnSize)][i] = queue[front]->val;
if(queue[front]->left != NULL)
queue[rear++] = queue[front]->left;

if(queue[front]->right != NULL)
queue[rear++] = queue[front]->right;

front++;
}
(*returnColumnSizes)[*returnSize] = cha; //这句zhejvlueluelue
(*returnSize)++;
}
}
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes){
*returnSize = 0;
if(root == NULL)
return NULL;

int **returns = (int **)malloc(sizeof(int*)*1010);

*returnColumnSizes = (int *)malloc(sizeof(int)*1010);
bfs(root,returns,returnSize,returnColumnSizes);
return returns;
}


#### 前序 + 中序 构建二叉树

/*

*/
struct TreeNode* dfs(int preorder[],int p_start,int p_end,int inorder[],int i_start,int i_end)
{
if(p_start == p_end)
return NULL;
int root = preorder[p_start];
int i_index;
for(int i = i_start;i < i_end;i++)
{
if(inorder[i] == root)
{
i_index = i;
break;
}
}
int p_num = i_index-i_start;
struct TreeNode* t = (struct TreeNode*)malloc(sizeof(struct TreeNode)*1);
t->val = root;
t->left = dfs(preorder,p_start+1,p_start+p_num+1,inorder,i_start,i_index);
t->right = dfs(preorder,p_start+p_num+1,p_end,inorder,i_index+1,i_end);
return t;
}
struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){
return dfs(preorder,0,preorderSize,inorder,0,inorderSize);
}


#### 有序数组转为二叉搜索树

struct TreeNode* dfs(int returns[],int low,int high)
{
if(low > high)
return NULL;

int mid = (low + high)/2;
struct TreeNode *t = (struct TreeNode* )malloc(sizeof(struct TreeNode)*1);
t->val = returns[mid];
t->left = dfs(returns,low,mid-1);
t->right = dfs(returns,mid+1,high);
return t;
}

struct TreeNode* sortedArrayToBST(int* nums, int numsSize){
return dfs(nums,0,numsSize-1);
}


#### 将二叉搜索树变平衡

struct TreeNode* dfs(int returns[],int low,int high)
{
if(low > high)
return NULL;

int mid = (low + high)/2;
struct TreeNode *t = (struct TreeNode* )malloc(sizeof(struct TreeNode)*1);
t->val = returns[mid];
t->left = dfs(returns,low,mid-1);
t->right = dfs(returns,mid+1,high);
return t;
}

void visit(struct TreeNode* root,int returns[],int *returnSize)
{
if(root == NULL)
return;
visit(root->left,returns,returnSize);
returns[(*returnSize)++] = root->val;
visit(root->right,returns,returnSize);
}

struct TreeNode* balanceBST(struct TreeNode* root){
//先遍历 存储到一个数组中，将整棵树 以一个 升序序列存放
int *returns = (int *)malloc(sizeof(int)* 10010);
int returnSize = 0;
visit(root,returns,&returnSize);
//再以中间建立 二叉搜索平衡树
return dfs(returns,0,returnSize-1);
}


#### 二叉树的最近公共祖先

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     struct TreeNode *left;
*     struct TreeNode *right;
* };
*/
struct TreeNode* dfs(struct TreeNode* root,struct TreeNode* p,struct TreeNode* q)
{
struct TreeNode* l,* r;
if(root == NULL)
return NULL;
if(root == p || root == q)
return root;
l = dfs(root->left,p,q);
r = dfs(root->right,p,q);
if(l != NULL && r != NULL)
return root;
else if(l == NULL && r!= NULL)
return r;
else
return l;
}

struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
//已知层序遍历的数组
return dfs(root,p,q);
}


#### 层数最深的叶子节点的和

/*

*/
/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     struct TreeNode *left;
*     struct TreeNode *right;
* };
*/
struct TreeNode* dfs(struct TreeNode* root,int deepth,int * sum,int *max_deepth)
{
if(root == NULL)
return NULL;
if(deepth > (*max_deepth))
{
(*max_deepth) = deepth;
(*sum) = 0; //guiling heihei
}
struct TreeNode *left,*right;
left = dfs(root->left,deepth+1,sum,max_deepth);
right = dfs(root->right,deepth+1,sum,max_deepth);
if(left == NULL && right == NULL && deepth == (*max_deepth))
(*sum) += root->val;
return root;
}

int deepestLeavesSum(struct TreeNode* root){
int sum = 0;
if(root == NULL)
return 0;
int max_deepth = 0;
dfs(root,0,&sum,&max_deepth);
return sum;
}


#### 对称二叉树

bool dfs(struct TreeNode* left_,struct TreeNode* right_)
{
if(left_ == NULL &&right_ == NULL)
return true;
if(left_ == NULL || right_ == NULL || right_->val != left_->val)
return false;
// 左的左子树和右的右子树	左的右子树和右的左子树 均互相对称
return dfs(left_->left,right_->right) && dfs(left_->right,right_->left);
}

bool isSymmetric(struct TreeNode* root){
if(root == NULL)
return true;
return dfs(root->left, root->right);
}


#### 二叉树的右视图

/*
bfs 记录每一层的最后一个节点
*/
int* rightSideView(struct TreeNode* root, int* returnSize){
*returnSize = 0;
if(root == NULL)
return NULL;
int *returns = (int *)malloc(sizeof(int)*110);
struct TreeNode* queue[120];
int front = 0;
int rear = 0;
memset(returns,0,sizeof(returns));
queue[rear++] = root;
while(front != rear)
{
int cha = rear - front;
while(cha--)
{
if(queue[front]->left != NULL)
queue[rear++] = queue[front]->left;
if(queue[front]->right != NULL)
queue[rear++] = queue[front]->right;
front++;
}
returns[(*returnSize)++] = queue[front-1]->val;
}
return returns;
}


### 排序

#### 插入 冒泡 选择

em 首先有请 n 2 n^2 的登场

#### 双轴快排

void swap(int *a,int *b)
{
int t = *a;
*a = *b;
*b = t;
}
void sort(int *nums,int start,int end)
{
if(start > end) return;
int left = start;
int right = end;

if(nums[start] == nums[end])
{
for(int i = start;i < end;i++)
{
if(nums[i] != nums[end])
{
swap(&nums[i],&nums[start]);
break;
}
}
}
if(nums[start] > nums[end])
swap(&nums[start],&nums[end]);

int privot1 = nums[start];
int privot2 = nums[end];
while(left+1 <= end && nums[left+1] < privot1)
left++;
while(right-1 >= start && nums[right-1] > privot2)
right--;
int k = left+1;

while(k < right)
{
if(nums[k] < privot1)
{
left++;
swap(&nums[left],&nums[k]);
k++;
}
else if(nums[k] <= privot2)
k++;
else
{
right--;
swap(&nums[right],&nums[k]);
}
}
swap(&nums[left],&nums[start]);
swap(&nums[right],&nums[end]);
sort(nums,start,left-1);
sort(nums,left+1,right-1);
sort(nums,right+1,end);
}
int* sortArray(int* nums, int numsSize, int* returnSize){
int start,end,k,left,right;
*returnSize = numsSize;
start = 0;
end = numsSize - 1;
sort(nums,start,end);
return nums;
}


#### 按奇偶排序数组——快排

void swap(int *a,int *b)
{
int t = *a;
*a = *b;
*b = t;
}
int* sortArrayByParity(int* nums, int numsSize, int* returnSize){
//kuaipaima
*returnSize = numsSize;
int i,j;
for(i = 0,j = numsSize-1;i < j;)
{
if(nums[i]%2 == 0)
i++;
if(nums[j]%2 == 1)
j--;
if(i > j)
break;
swap(&nums[i],&nums[j]);
}
return nums;
}


#### 荷兰国旗问题——颜色分类——快排

// 你的 c 是 n 方的复杂度，建议看一下边 n 的复杂度
void sortColors(int* nums, int numsSize){
for(int i = 1;i < numsSize;i++)
{
int t = nums[i];
int j = i;
for(;j > 0;j--)
{
if(t < nums[j-1])
nums[j] = nums[j-1];
else
break;
}
nums[j] = t;
}
}
//--------------------------------------------------------------------------------------------------------//
void swap(int *a, int *b) {
int tp = *a;
*a = *b;
*b = tp;
}
void sortColors(int* nums, int numsSize){
// 初始化左指针为第一个元素的前一个位置  右指针为最后一个元素的后一个位置
// 这样相当于左指针所指向的及其左边的元素均为0
//          右指针所指向的及其右边的元素均为2
int l = -1, r = numsSize;
// 从左到右遍历每一个元素
for (int i = 0; i < r; ++i) {
// 如果是 0，和左指针的下一个元素交换
if (nums[i] == 0) {
swap(&nums[++l], &nums[i]);
} else if (nums[i] == 2) {
// 如果是2，和右指针的前一个元素交换，但是交换之后需重新判断当前位置元素的情况，所以对 i--
swap(&nums[--r], &nums[i--]);
}
// 如果是 1 不做处理
}
}


#### 数组中的多数元素——快排

void swap(int a[],int x,int y)
{
int t = a[x];
a[x] = a[y];
a[y] = t;
}
int partition(int a[],int start,int end) //分区 找枢纽 然后left right交换数据
{
int temp = a[start];
int left = start + 1;
int right = end;
while(left < right)
{
while(left < right && a[left] <= temp) left++;
while(left < right && a[right] >= temp) right--;
if(left < right)
{
swap(a,left,right);
left++;
right--;
}
}
if(right == left && a[right] > temp) right--;
swap(a,right,start);
return right;
}
void quicksort(int a[],int start,int end) //快排 左右排序 递归
{
if(start >= end) return;
int mid = partition(a,start,end);
quicksort(a,start,mid-1);
quicksort(a,mid+1,end);
}
int majorityElement(int* nums, int numsSize){
quicksort(nums,0,numsSize-1);
return nums[numsSize/2];
}


#### 逆序对问题——归并

int merge(int a[],int com[],int low,int mid,int high,int count)
{
for(int i = low; i <= high;i++)
com[i] = a[i];

int i,j,k;
for(i = low,j = mid+1,k = low;i <= mid && j <= high;k++)
{
if(com[i] <= com[j])
{
a[k] = com[i];
i++;
}
else
{
a[k] = com[j];
j++;
count += mid-i+1; //每一次后边的小放到前面就形成了前一个数组所剩元素数量的逆序对
}
}
while(i <= mid) a[k++] = com[i++];
while(j <= high) a[k++] = com[j++];
return count;
}
int mergesort(int a[],int com[],int low,int high,int count)
{
if(low < high)
{
int mid = (low+high)/2;
count = mergesort(a,com,low,mid,count);
count = mergesort(a,com,mid+1,high,count);
count = merge(a,com,low,mid,high,count);
}
return count;
}

int reversePairs(int* nums, int numsSize){
int count = 0;
int *com = (int *)malloc(sizeof(int)*numsSize);
count = mergesort(nums,com,0,numsSize-1,count);
return count;
}


#### Top K 问题——堆排

void buildmaxheap(int * a,int len)
{
for(int i = len/2;i > 0;i--)
}

a[0] = a[k];
for(int i = k*2;i <= len;i*=2)
{
if(i < len &&a[i] < a[i+1])
i++;
if(a[0] >= a[i])
break;
else {
a[k] = a[i];
k = i;
}
}
a[k] = a[0];
return;
}
int findKthLargest(int* nums, int numsSize, int k){
int * a = (int *)malloc(sizeof(int )*(numsSize+1));
int m = 1;
for(int j = 0;j < numsSize;j++)
a[m++] = nums[j];

int len = numsSize; //len是第n个 可以取到值，所以应该等于nums 这样就alen有意义
buildmaxheap(a,len);

for(int i = len,m = 0;m < k-1 ;i--,m++)
{
a[1] = a[i];
}
return a[1];
}
// ------------------------------------------------------------------------//
void swap(int arr[],int i,int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
int findKthLargest(int* nums, int numsSize, int k){
int maxindex,minindex;
int i,j;
for(i = 0;i < numsSize/2;i++)
{
maxindex = i;
minindex = i;
for(j = i+1;j < numsSize-i;j++)
{
if(nums[maxindex] < nums[j])
maxindex = j;
if(nums[minindex] > nums[j])
minindex = j;
}
if(maxindex == minindex)
break;
swap(nums,maxindex,i);
if(minindex == i)
minindex = maxindex;
swap(nums,minindex,numsSize-1-i);
}

return nums[k-1];
}


#### 最小的 K 个数——堆排

//堆排序
{
int temp = a[k];
for(int j = k*2 ;j <= len;j *= 2)//第2个结点-1 = 下标
{
if(j < len && a[j] > a[j+1])
j++;
if(a[j] >= temp)
break;
else
{
a[k] = a[j];
k = j;
}
}
a[k] = temp;
}
void buildheap(int a[],int len)
{
for(int j = len/2;j > 0;j--)
}
void swap(int *a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
int* getLeastNumbers(int* arr, int arrSize, int k, int* returnSize){
int a[arrSize+1];
int m = 1;
for(int j = 0;j < arrSize;j++)
a[m++] = arr[j];

*returnSize = k;
int *returns = (int *)malloc(sizeof(int) * k);
buildheap(a,arrSize);
for(int i = 0,x = arrSize;i < k;i++,x--)
{
returns[i] = a[1];
swap(&a[1],&a[x]);
}
return returns;
}


#### 最大间距——基排

void copy(int arr[],int nums[],int len)
{
for(int i = 0;i < len;i++)
nums[i] = arr[i];
}
void set_0(int arr[],int len)
{
for(int i = 0;i < len;i++)
arr[i] = 0;
}
int maximumGap(int* nums, int numsSize){
if(numsSize < 2) return 0;
int cha = 0;
int max = 0,max_length = 0;
int count[10];
int arr[numsSize];
int ten = 1;
set_0(arr,numsSize);
for(int i = 0;i < numsSize;i++)
{
if(max < nums[i])
max = nums[i];
}
while(max > 0)
{
max = max / 10;
max_length++;
}
set_0(count,10);
while(max_length--)
{
for(int j = 0;j < numsSize;j++)
{
int r = nums[j] / ten % 10;
count[r]++;
}
for(int k = 1;k < 10;k++)
count[k] += count[k-1];
for(int m = numsSize-1;m >= 0;m--)
{
int r = nums[m] / ten % 10;
arr[count[r]-1] = nums[m];
count[r]--;
}
copy(arr,nums,numsSize);
ten *= 10;
set_0(count,10);
}
for(int k = 0; k < numsSize-1;k++)
{
if(cha < nums[k+1]-nums[k])
cha = nums[k+1] - nums[k];
}
return cha;
}


#### 排序杂题

##### 相对名次

char ** findRelativeRanks(int* score, int scoreSize, int* returnSize){
*returnSize = scoreSize;
int a[scoreSize];
for(int m = 0;m < scoreSize;m++)
a[m] = score[m];

char **returns = (char **)malloc(sizeof(char*)*scoreSize);
int temp,index;
for(int dk = scoreSize/2;dk > 0;dk /= 2)
{
for(int i = dk;i < scoreSize;i++)
{
if(score[i-dk] < score[i])
{
temp = score[i];
index = i-dk;
while(index >= 0 && temp > score[index])
{
score[index+dk] = score[index];
index -= dk;
}
score[index+dk] = temp;
}
}
}
for(int k = 0;k < scoreSize;k++)
{
for(int m = 0;m < scoreSize;m++)
{
if(a[k] == score[m])
{
if(m == 0)
returns[k] = "Gold Medal";
else if(m == 1)
returns[k] = "Silver Medal";
else if(m == 2)
returns[k] = "Bronze Medal";
else
{
returns[k] = (char*)malloc(sizeof(char)*10);
sprintf(returns[k],"%d",m+1) ;
}
break;
}
}
}
return returns;
}


### 双指针

#### 无重复字符的最长子串

/*

*/
int max(int a,int b)
{
return a > b ? a : b;
}
int lengthOfLongestSubstring(char* s) {
int n = strlen(s);
int i = 0, j = 0;
bool exist[256] = {false};
int max_len = 0;
while(j < n){
if(exist[s[j]]){
max_len = max(max_len, j - i);
while(s[i] != s[j]){
exist[s[i]] = false;
i++;
}
i++;
j++;
}else{
exist[s[j]] = true;
j++;
}
}
max_len = max(max_len, n - i);
return max_len;
}


### 二分

#### 旋转数组的最小数字

int minArray(int* numbers, int numbersSize){
//生活太累了，我可以邀请你去云朵☁️上打呼噜吗
// 好呀好呀 那真是太开心啦！
// int min_num = numbers[0];
int low = 0;
int mid = (low + high)/2;
while(low < high)
{
if(numbers[mid] > numbers[high])
low = mid+1;
else if(numbers[mid] < numbers[high])
high = mid;
else
high--;
mid = (low+high)/2;
}
return numbers[low];
}


#### 0~n-1 中缺失的数字

/*

*/
int missingNumber(int* nums, int numsSize){
int mid;
int low = 0;
int high = numsSize-1;
if(nums[low] == 1)
return low;
if(nums[high] == high)
return high+1;
while(low < high)
{
mid = (low+high)/2;
if(nums[mid] != mid)
high = mid;
else
low = mid+1;
}
return low;
}


### 深度优先搜索 dfs

#### 括号生成

void bracket(int left,int right,int n,char arr[],int idx,char c,char **returns,int *returnSize)
{
if(left < right || left > n || right > n)
return;
if(left == n && right == n)
{
returns[(*returnSize)] = (char *)calloc((2*n+1),sizeof(char));
strcpy(returns[(*returnSize)],arr);
(*returnSize)++;
return;
}
arr[idx] = '(';
bracket(left+1,right,n,arr,idx+1,'(',returns,returnSize);
arr[idx] = ')';
bracket(left,right+1,n,arr,idx+1,')',returns,returnSize);
return;
}

char ** generateParenthesis(int n, int* returnSize){
*returnSize = 0;
char ** returns = (char **)malloc(sizeof(char *)*1500);
char * arr = (char *)calloc((2*n+1),sizeof(char));
bracket(0,0,n,arr,0,'(',returns,returnSize);
return returns;
}


#### 路径总和

void digui(struct TreeNode* root,int targetSum,int arr[],int **returns,int* returnSize,int index,int **returnColumnSizes)
{
if(root == NULL) return;
arr[index] = root->val;
targetSum -= root->val;

if(targetSum == 0 && root->left == NULL && root->right == NULL)
{
returns[(*returnSize)] = (int *)calloc((index+1),sizeof(int ));
for(int i = 0;i <= index;i++)
returns[(*returnSize)][i] = arr[i];

(*returnColumnSizes)[*returnSize] = index+1;
(*returnSize)++;
return;
}
digui(root->left,targetSum,arr,returns,returnSize,index+1,returnColumnSizes);
digui(root->right,targetSum,arr,returns,returnSize,index+1,returnColumnSizes);
return ;
}

int** pathSum(struct TreeNode* root, int targetSum, int* returnSize, int** returnColumnSizes){
*returnSize = 0;
*returnColumnSizes = (int *)malloc(sizeof(int)*5050);
int **returns = (int **)malloc(sizeof(int *)*5050);
int *arr = (int *)malloc(sizeof(int)*5050);
int index = 0;
digui(root,targetSum,arr,returns,returnSize,index,returnColumnSizes);
return returns;
}


### 贪心

#### 三元组最小距离

/*

1. 如果往后移动 k，则三元组的距离会增大；
2. 如果移动 j：
2.1 如果 s2[j + 1] > s3[k]，则三元组距离增大
2.2 如果 s2[j + 1] <=  s3[k]，则三元组距离不变
3. 如果移动 i:
3.1 如果 s1[i + 1] <= s3[k]，则距离减小
3.2 如果 s1[i + 1] > s3[k]，则距离可能增大或者减小

*/
#include<bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;

int main() {
int l, m, n;
scanf("%d %d %d", &l, &m, &n);

long long s1[N], s2[N], s3[N];
for (int i = 0; i < l; ++i) scanf("%lld", &s1[i]);
for (int i = 0; i < m; ++i) scanf("%lld", &s2[i]);
for (int i = 0; i < n; ++i) scanf("%lld", &s3[i]);

long long ans = LONG_LONG_MAX;
for (int i = 0, j = 0, k = 0; i < l && j < m && k < n; ) {
long long dis = abs(s1[i] - s2[j]) + abs(s2[j] - s3[k]) + abs(s1[i] - s3[k]);
ans = min(ans, dis);

if (s1[i] <= s2[j] && s1[i] <= s3[k]) i++;
else if (s2[j] <= s1[i] && s2[j] <= s3[k]) j++;
else if (s3[k] <= s2[j] && s3[k] <= s1[i]) k++;
}
cout << ans << endl;
return 0;
}


### 动态规划

#### 最大子数组和

// nums[i] 表示以 i 结尾的最大子数组和
int maxSubArray(int* nums, int numsSize){
int sum = nums[0];
for(int i = 1;i < numsSize;i++)
{
if(nums[i-1] > 0)
nums[i] += nums[i-1];
if(nums[i] > sum)
sum = nums[i];
}
return sum;
}


#### 最大乘积子数组

// 小苏的代码 em 周久良和孟鹤堂 都搬上来了
int max_num(int a,int b,int c)
{
if(a >= b && a >= c)
return a;
else if(b >= a && b >= c)
return b;
else if(c >= a && c >= b)
return c;
else
return 0;
}
int min_num(int a,int b,int c)
{
if(a <= b && a <= c)
return a;
else if(b <= a && b <= c)
return b;
else if(c <= a && c <= b)
return c;
else
return 0;
}
int maxProduct(int* nums, int numsSize){
if(numsSize == 0)
return 0;
// 以第 i 个元素结尾的子数组乘积最大值
int zjl_max = nums[0];
// 以第 i 个元素结尾的子数组乘积最小值
int zjl_min = nums[0];
int mht_max = nums[0];
for(int i = 1;i < numsSize;i++)
{
int temp = zjl_max;
zjl_max = max_num(zjl_max*nums[i],zjl_min*nums[i],nums[i]);
zjl_min = min_num(temp*nums[i],zjl_min*nums[i],nums[i]);
if(mht_max < zjl_max)
mht_max = zjl_max;
}
return mht_max;
}

// dage 的优雅
int min(int a, int b) {return a > b ? b : a;}
int max(int a, int b) {return a > b ? a : b;}
int maxProduct(int* nums, int numsSize){
int ans = nums[0];
int dp_mi[numsSize + 5];
int dp_ma[numsSize + 5];
dp_ma[0] = dp_mi[0] = nums[0];
for (int i = 1; i < numsSize; ++i) {
dp_mi[i] = min(nums[i], min(nums[i] * dp_mi[i - 1], nums[i] * dp_ma[i - 1]));
dp_ma[i] = max(nums[i], max(nums[i] * dp_mi[i - 1], nums[i] * dp_ma[i - 1]));
ans = max(ans, dp_ma[i]);
}
return ans;
}


#### 最长公共子序列

/*
dp[i][j] 表示第一个串的前 i 个元素和第二个串的前 j 个元素的最长公共子序列

第一个串的前 i 个元素和第二个串的前 j-1 个元素的最长公共子序列长度（dp[i][j-1]）的最大值
*/
int max(int a,int b)
{
return a > b ? a : b;
}
int longestCommonSubsequence(char * text1, char * text2){
int len1 = strlen(text1);
int len2 = strlen(text2);
int dp[1010][1010];
int i,j;
dp[0][0] = 0;
for(i = 1;i <= strlen(text1);i++)
{
for(j = 1;j <= strlen(text2);j++)
{
if(text1[i-1] == text2[j-1])
dp[i][j] = dp[i-1][j-1]+1;
else
dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
}
}
return dp[len1][len2];
}


#### 最长公共子数组（最长重复子数组）

/*
dp[i][j] 表示第一个串以第 i 个元素结尾和第二个串的以第 j 个元素结尾的最长公共子数组（当然这里你是倒序的啦，意思是一样的）

*/
int max(int a,int b)
{
return a > b ? a : b;
}
int findLength(int* nums1, int nums1Size, int* nums2, int nums2Size){
int dp[nums1Size+1][nums2Size+1];
memset(dp, 0, sizeof(dp));
dp[nums1Size][nums2Size] = 0;
int ans = 0;
for(int i = nums1Size-1;i >= 0;i--)
{
for(int j = nums2Size-1;j >= 0;j--)
{
if(nums1[i] == nums2[j])
dp[i][j] = dp[i+1][j+1]+1;
else
dp[i][j] = 0;
ans = max(ans,dp[i][j]);
}
}
return ans;
}


#### 最长递增子序列

• 如果求的是最长递增子数组呢
/*
dp[i] 表示以 i 结尾的递增子序列的最大长度
*/
int max(int a,int b)
{
return a > b ? a : b;
}
int lengthOfLIS(int* nums, int numsSize){
int max_num = 1;
int dp[numsSize];
// memset(dp,1,sizeof(dp));
dp[0] = 1;
for(int i = 1;i < numsSize;i++)
{
dp[i] = 1;
for(int j = 0;j < i;j++)
{
// 相当于是将 第 i 个数字 加在 第 j 个数字之后，所以是 dp[j]+1，这里求的是 dp[i] 的最大值，因此是 max(dp[i], dp[j]+1)
if(nums[j] < nums[i])
dp[i] = max(dp[i],dp[j]+1);
}
// 更新结果
max_num = max(max_num,dp[i]);
}
return max_num;
}


em 如果求的是最长递增子数组的话那么当然是 双指针啦！

#### 01背包 *

//板子板子
#include <bits/stdc++.h>
using namespace std;

const int N = 1010;

int n,m;
int f[N][N];
int v[N],w[N];

int main()
{
cin >> n >> m;
//小白想检验一下生成的f数组是不是全0数组
// for(int j = 0;j < n;j++) cout<<f[j][4];
for(int i = 1;i <= n;i++)
{
cin >> v[i] >> w[i];
}
//下面这个循环是 依次考虑 当第i个物品时，体积j依次增大，直到大于v[i]时，即当前可以装下第i个物品，即拥有了第i个物品的价值。下面进行降维优化时，j从最大体积m依次减小考虑情况。
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
f[i][j] = f[i - 1][j];
if(j >= v[i])
{
f[i][j] = max(f[i][j],f[i - 1][j - v[i]] + w[i]);
//小白手动跑了一遍检验发现 f[n][m]已经是最大的价值 因为赋值时进行了选择
}
}
}

// int res = 0;
// for(int i = 0;i <= m;i++)
// {
//     res = max(res,f[n][i]);
// }
cout<<f[n][m]<<endl;
return 0;
}

// 优化
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;

int n,m;
int f[N]; //这里进行降维优化
int v[N],w[N];

int main()
{
cin >> n >> m;
for(int i = 1;i <= n;i++)
{
cin >> v[i] >> w[i];
}
for(int i = 1;i <= n;i++)
{
for(int j = m;j >= v[i];j--)
{
//由于此时变成了一位数组 由于比较的是和它前一位f[i-1][j-v[i]]为了更好地表示发生变化，我们应选择体积从最大的体积m依次递减
f[j] = max(f[j],f[j - v[i]] + w[i]);
}
}
cout<<f[m]<<endl;
return 0;
}

// dage 代码
#include<bits/stdc++.h>
using namespace std;

const int N = 1005;
const int V = 1005;
int n, v;
int dp[N];
// int size[N], weight[N];

/*
dp[i][j] 表示前 i 件物品背包容量为 j 的情况下可以取到的最大价值

1. dp[i - 1][j] 表示不取第 i 件物品得到的价值，即前 i-1 件物品，背包容量为 j 是可以得到的最大价值
2. dp[i - 1][j - v] + w 表示取第 i 件物品得到的价值。即【前 i-1 件物品】在【背包容量为 j-v 】的时候【可以得到最大价值】加上【第 i 件物品的价值w】
--------------优化--------------

dp[i] 表示【当前物品及之前物品】，在 【体积为 i】的情况下可以取得的最大值

*/
// 封装的 01 背包，v 是背包的总体积，volume 是当前物品的体积，weight 是当前物体的价值
// 01 背包倒叙遍历
void zero_one_package(int volume, int weight) {
for (int i = v; i >= volume; --i) {
dp[i] = max(dp[i], dp[i - volume] + weight);
}
}

int main() {
cin >> n >> v;
memset(dp, 0, sizeof dp);
int volume, weight;
// 获取 n 个物品的体积和价值
for (int i = 0; i < n; ++i) {
cin >> volume >> weight;
zero_one_package(volume, weight);
}
cout << dp[v] << endl;
return 0;
}


#### 完全背包 *

#include<bits/stdc++.h>
using namespace std;

const int N = 1005;
const int V = 1005;
int n, v;
int dp[N];

// 封装的 完全 背包，v 是背包的总体积，volume 是当前物品的体积，weight 是当前物体的价值
// 完全 背包正序遍历
/*

*/
void complete_package(int volume, int weight) {
for (int i = volume; i <= v; ++i) {
dp[i] = max(dp[i], dp[i - volume] + weight);
}
}

int main() {
cin >> n >> v;
int volume, weight;
memset(dp, 0, sizeof dp);
for (int i = 0; i < n; ++i) {
cin >> volume >> weight;
complete_package(volume, weight);
}
cout << dp[v] << endl;
return 0;
}


#### 零钱兑换——完全背包变体 *

// 一看无限次就是完全背包【指遍历顺序是从前往后】
/*

背包大小是 20，只有一件物品的体积是 3，价值为 2，则最大的价值为 18*2 = 36。
有  dp[20] = dp[17] + 2;
dp[17] = dp[14] + 2;
...
dp[5] = dp[2] + 2; 这样的状态转移过程

因为要凑成 20 需要凑成 17，要凑成 17 需要 14，最终需要凑成 2，但是只有 3 的面额，所有无法凑成 2

1. 即对于不要求装满的那种情况下，我最终的情况可以由 dp[0]~dp[20] 任意一种情况转移过来。比如只有体积为 19 的物品，则 dp[20] = dp[1] + w，即 dp[20] 由初始的 dp[1] 状态转移过来
2. 而对于凑钱的问题（或者说要求正好装满的情况下）则不行，你必须最终由 dp[0] 转移过来。也就是说，dp[1]~dp[20] 不能作为最初始的合法状态。
*/
int min(int a, int b) { return a > b ? b : a; }

int coinChange(int* coins, int coinsSize, int amount){
int dp[amount + 5];
// 所有的状态都需要从 0 转移而来，所有其它需要初始化为最大（因为要最小钱币数）
memset(dp, 0x3f, sizeof dp);
dp[0] = 0;
for (int i = 0; i < coinsSize; ++i) {
for (int j = coins[i]; j <= amount; ++j) {
dp[j] = min(dp[j], dp[j - coins[i]] + 1);
}
}
return dp[amount] > amount ? -1 : dp[amount];
}


#### 零钱兑换II ——完全背包变体 *

/*

dp[j] 表示组合成 j 面额的方案数

*/
int change(int amount, int* coins, int coinsSize){
int dp[amount + 5];
// 所有的状态都需要从 0 转移而来，最初组合成 0 的方案为 1，其它的方案为 0
memset(dp, 0, sizeof dp);
dp[0] = 1;
for (int i = 0; i < coinsSize; ++i) {
for (int j = coins[i]; j <= amount; ++j) {
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}


### 杂题

#### 回文数

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;
}


#### 字符串压缩——模拟

int compress(char* chars, int charsSize){
int index = 0;
int i,j;
{
j = i+1;
// 要注意先判断是否越界呀小苏 小脑袋瓜 记住！记住！记住！！！
while(j < charsSize && chars[j] == chars[i])
j++;

if(j-i > 1)
{
chars[index++] = chars[i];
int d = j-i;
int d_index = 0;
int arr[5];
while(d > 0)
{
arr[d_index] = d%10;
d = d/10;
d_index++;
}
while(d_index--)
{
chars[index++] = arr[d_index]+'0';
}
}
else if(j-i == 1)
chars[index++] = chars[i];

break;
i = j;
}
}


ns 表示不同面额的硬币，另给一个整数 amount 表示总金额。

/*

dp[j] 表示组合成 j 面额的方案数

*/
int change(int amount, int* coins, int coinsSize){
int dp[amount + 5];
// 所有的状态都需要从 0 转移而来，最初组合成 0 的方案为 1，其它的方案为 0
memset(dp, 0, sizeof dp);
dp[0] = 1;
for (int i = 0; i < coinsSize; ++i) {
for (int j = coins[i]; j <= amount; ++j) {
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}


### 杂题

#### 回文数

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;
}


#### 字符串压缩——模拟

int compress(char* chars, int charsSize){
int index = 0;
int i,j;
{
j = i+1;
// 要注意先判断是否越界呀小苏 小脑袋瓜 记住！记住！记住！！！
while(j < charsSize && chars[j] == chars[i])
j++;

if(j-i > 1)
{
chars[index++] = chars[i];
int d = j-i;
int d_index = 0;
int arr[5];
while(d > 0)
{
arr[d_index] = d%10;
d = d/10;
d_index++;
}
while(d_index--)
{
chars[index++] = arr[d_index]+'0';
}
}
else if(j-i == 1)
chars[index++] = chars[i];

break;
i = j;
}
}

• 34
点赞
• 451
收藏
觉得还不错? 一键收藏
• 打赏
• 9
评论
10-27 2099
08-13 927
08-24 9271
06-03 1万+
11-26
02-18
06-03
10-24
05-21 116
04-22 1万+
11-11 872

_苏沐

¥1 ¥2 ¥4 ¥6 ¥10 ¥20

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、付费专栏及课程。