文章目录
1.链表oj
2.栈和队列oj
文章内容
1.链表oj
1. 给定一个链表,每个结点包含一个额外增加的随机指针,该指针可以指向链表中的任何结点
或空结点。要求返回这个链表的深度拷贝。力扣
该题不仅要求复制链表,而且每个节点有两个指针域,一个指向下一个节点,一个指向随机节点。
思路一:暴力求解
第一,复制一个链表出来
第二,复制random,但是原链表random指向的下一个节点,如何在复制的链表中找到?
我们可以通过原链表的数据域来确定吗?如果不同节点存储相同的数据,这时我们怎么去判定复制节点中random所指向的节点呢?我们可以将每个节点的下标,以及random指向节点的下标单独存储起来,这样我们在复制的链表中便可以轻松找到random指向的节点。但是这种方法的空间复杂度是O(N^2)。不妨换种思路?!!
思路二:
思路图:
struct Node* copyRandomList(struct Node* head) {
struct Node* cur = head;
//在原节点后链接新节点
while(cur)
{
struct Node* next =cur->next;
struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
copy->val = cur->val;
//链接
cur->next = copy;
copy->next = next;
cur = next;
}
//复制random
cur = head;
while(cur)
{
struct Node* copy = cur->next;
struct Node* next = copy->next;
if(cur->random == NULL)
{
copy->random = NULL;
}
else
{
copy->random = cur->random->next;
}
//往后走
cur = next;
}
cur = head;
struct Node* copyhead = NULL;
struct Node* copytail = NULL;
while(cur)
{
struct Node* copy = cur->next;
struct Node* next = copy->next;
if(copytail == NULL)
{
copyhead = copytail = copy;
}
else
{
copytail->next = copy;
copytail = copytail->next;
}
//恢复原链表
cur->next = next;
cur = next;
}
return copyhead;
}
2.栈和队列oj
1. 括号匹配问题。力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
思路:将所有的左括号入栈,而右括号不入栈。栈顶的元素都需要与下一个不入栈的元素(也就是右括号),相比较看是否为同一类型的,这样设计从前到后比较了每一对相邻最近的左、右括号。假如某一对相邻最近的左、右括号不匹配便返回假。
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* ps);
void STDestroy(ST* ps);
void STPush(ST* ps, STDataType x);
void STPop(ST* ps);
STDataType STTop(ST* ps);
int STSize(ST* ps);
bool STEmpty(ST* ps);
void STInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->capacity = 0;
ps->top = 0;
}
void STDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->top = ps->capacity = 0;
}
void STPush(ST* ps, STDataType x)
{
assert(ps);
// 11:40
if (ps->top == ps->capacity)
{
int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * newCapacity);
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
ps->a = tmp;
ps->capacity = newCapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
void STPop(ST* ps)
{
assert(ps);
//
assert(ps->top > 0);
--ps->top;
}
STDataType STTop(ST* ps)
{
assert(ps);
//
assert(ps->top > 0);
return ps->a[ps->top - 1];
}
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
bool isValid(char * s){
ST st;
STInit(&st);
char topval;
while(*s)
{
if(*s == '(' || *s == '{' || *s == '[')
{
STPush(&st,*s);
}
else
{
if(STEmpty(&st))
{
STDestroy(&st);
return false;
}
topval = STTop(&st);
STPop(&st);
if((*s == ')' && topval != '(' )
||(*s == ']' && topval != '[' )
||(*s == '}' && topval != '{' )
)
{
STDestroy(&st);
return false;
}
}
++s;
}
bool ret = STEmpty(&st);
STDestroy(&st);
return ret;
}
2. 用队列实现栈。力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
思路: 入队时入不为空的队列。出队队列时,不为空的队列的前n-1个元素入空队列,出不为空的队列的最后一个元素。也就是一个队列保持为空,一个保持不为空。
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode * next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
int size;
}Que;
//初始化
void QueueInit(Que* pq);
//销毁
void QueueDestroy(Que* pq);
//入队
void QueuePush(Que* pq, QDataType x);
//出队
void QueuePop(Que* pq);
//判空
bool QueueEmpty(Que* pq);
//取队头元素
QDataType QueueFront(Que* pq);
//去队尾元素
QDataType QueueBack(Que* pq);
//计数
int QueueSize(Que* pq);
//初始化
void QueueInit(Que* pq)
{
pq->head = NULL;
pq->tail = NULL;
pq->size =0;
}
//销毁
void QueueDestroy(Que* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
pq->size = 0;
}
//入队
void QueuePush(Que* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
if (pq->tail == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
pq->size++;
}
//出队
void QueuePop(Que* pq)
{
assert(pq);
assert(! QueueEmpty(pq));
if (pq->head->next == NULL)
{
free(pq->head);
pq->head =pq->tail = NULL;
}
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
pq->size--;
}
//取队头元素
QDataType QueueFront(Que* pq)
{
assert(pq);
assert(! QueueEmpty(pq));
return pq->head->data;
}
//去队尾元素
QDataType QueueBack(Que* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
//判空
bool QueueEmpty(Que* pq)
{
assert(pq);
return pq->head == NULL;
}
//计数
int QueueSize(Que* pq)
{
assert(pq);
return pq->size;
}
typedef struct {
Que q1;
Que q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* pst =(MyStack* )malloc(sizeof(MyStack));
QueueInit(&pst->q1);
QueueInit(&pst->q2);
return pst;
}
void myStackPush(MyStack* obj, int x) {
if(! QueueEmpty(&obj->q1))
{
QueuePush(&obj->q1,x);
}
else
{
QueuePush(&obj->q2,x);
}
}
int myStackPop(MyStack* obj) {
Que* empty = &obj->q1;
Que* nonempty = &obj->q2;
if(! QueueEmpty(&obj->q1))
{
empty = &obj->q2;
nonempty = &obj->q1;
}
while(QueueSize(nonempty)>1)
{
QueuePush(empty,QueueFront(nonempty));
QueuePop(nonempty);
}
int top = QueueFront(nonempty);
QueuePop(nonempty);
return top;
}
int myStackTop(MyStack* obj) {
if(! QueueEmpty(&obj->q1))
{
return QueueBack(&obj->q1);
}
else
{
return QueueBack(&obj->q2);
}
}
bool myStackEmpty(MyStack* obj) {
return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
3. 用栈实现队列。力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
思路:两个栈,一个入元素,另一个出元素。当出元素的栈为空时候,将入元素的栈压入出元素的栈。
typedef int STDataType;
typedef struct Stcak
{
STDataType* a;
int top;
int capacity;
}ST;
void STInit(ST* ps);
void STDestroy(ST* ps);
void STPush(ST* ps, STDataType x);
void STPop(ST* ps);
STDataType STTop(ST* ps);
int STSize(ST* ps);
bool STEmpty(ST* ps);
void STInit(ST* ps)
{
assert(ps);
ps->a = NULL;
ps->top = 0;
ps->capacity = 0;
}
void STDestroy(ST* ps)
{
assert(ps);
free(ps->a);
ps->a = NULL;
ps->capacity = ps->top = 0;
}
void STPush(ST* ps, STDataType x)
{
assert(ps);
if (ps->capacity == ps->top)
{
STDataType newcapacity = ps->capacity == 0 ? 4: (ps->capacity)* 2;
STDataType* tmp = (STDataType*) realloc(ps->a,sizeof(STDataType)* newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
ps->a = tmp;
ps->capacity = newcapacity;
}
ps->a[ps->top] = x;
ps->top++;
}
void STPop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
ps->top--;
}
STDataType STTop(ST* ps)
{
assert(ps);
assert(ps->top > 0);
return ps->a[ps->top-1];
}
int STSize(ST* ps)
{
assert(ps);
return ps->top;
}
bool STEmpty(ST* ps)
{
assert(ps);
return ps->top == 0;
}
typedef struct {
ST pushst;
ST popst;
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj =(MyQueue*) malloc(sizeof(MyQueue));
STInit(&obj->pushst);
STInit(&obj->popst);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
STPush(&obj->pushst,x);
}
int myQueuePeek(MyQueue* obj) {
if(STEmpty(&obj->popst))
{
while(!STEmpty(&obj->pushst))
{
STPush(&obj->popst,STTop(&obj->pushst));
STPop(&obj->pushst);
}
}
return STTop(&obj->popst);
}
int myQueuePop(MyQueue* obj) {
int front =myQueuePeek (obj);
STPop(&obj->popst);
return front;
}
bool myQueueEmpty(MyQueue* obj) {
return STEmpty(&obj->pushst) && STEmpty(&obj->popst);
}
void myQueueFree(MyQueue* obj) {
STDestroy(&obj->pushst);
STDestroy(&obj->popst);
free(obj);
}
4. 设计循环队列。力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
思路:
如何判断队列空 和 满 这是循环队列的关键所在,插入和弹出问题难度不大。
pop(弹出)
typedef struct {
int* a;
int front;
int rear;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a = (int* )malloc(sizeof(int) *(k+1));
obj->rear = obj->front = 0;
obj->k = k;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front == obj->rear;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->rear+1)%(obj->k+1) == obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->a[obj->rear]= value;
obj->rear++;
obj->rear %= obj->k+1;
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
obj->front++;
obj->front %= (obj->k+1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
else
return obj->a[(obj->rear+obj->k)% (obj->k+1)];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}