算法题合集(细分知识点)---------第一部分

文章目录


数组

189. 轮转数组

https://leetcode.cn/problems/rotate-array/description/
给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

void rotate(int* nums, int numsSize, int k) {
    k=k%numsSize;
    if(k>numsSize&&numsSize==1)
    return;
    if(k>numsSize&&numsSize==2){
        int tmp=*nums;
       *nums=nums[1];
        nums[1]=tmp;
        return;
    }
    int* newnums = (int*)malloc(sizeof(int) * numsSize * 2);

    for (int j = 2;j > 0;--j) {
        for (int i = 0;i < numsSize;++i) {//将数组复制两次到新数组
            if (j == 2) {
                newnums[i] = nums[i];
            }
            else {
                newnums[numsSize + i] = nums[i];
            }
        }
    }

    for (int i = 0;i < numsSize;i++) {
        nums[i] = newnums[numsSize+i-k];
    }
}

989. 数组形式的整数加法

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/add-to-array-form-of-integer

整数的 数组形式 num 是按照从左到右的顺序表示其数字的数组。
例如,对于 num = 1321 ,数组形式是 [1,3,2,1] 。给定 num ,整数的 数组形式 ,和整数 k ,返回 整数 num + k 的 数组形式 。

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

 int* addToArrayForm(int* num, int numSize, int k, int* returnSize) {
    int* res = malloc(sizeof(int) * fmax(10, numSize + 1));//fmax返回两者较大值
    *returnSize = 0;//返回一个数组指针 但是returnsize的意思是返回的长度是多少
    for (int i = numSize - 1; i >= 0; --i) {
        int sum = num[i] + k % 10;//将个位和个位的数字相加
        k /= 10;
        if (sum >= 10) {//如果在这个位置出现了进位
            k++;
            sum -= 10;
        }
        res[(*returnSize)++] = sum;//赋值给返回数组并数组返回长度自增
    }
    for (; k > 0; k /= 10) {//如果k还大于零 那么就说明还没有加完 但是原数组的值已经加完了 那么就直接将这个位数的值赋值给res数组中
        res[(*returnSize)++] = k % 10;
    }
    for (int i = 0; i < (*returnSize) / 2; i++) {//将数组进行反转
        int tmp = res[i];
        res[i] = res[(*returnSize) - 1 - i];
        res[(*returnSize) - 1 - i] = tmp;
    }
    return res;
}

88. 合并两个有序数组

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/merge-sorted-array

给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。

示例 1:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3][2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
//自己的解答
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    int count=0;
    int i=0,j=0;
    if(m==0){//nums1是没有元素参加时
        for(;j<n;j++)
            nums1[i++]=nums2[j];
        return;
    }
    int arr[m];
    for(i=0;i<m;i++){//nums1有元素参加时
        arr[i]=nums1[i];
    }
    i=0;
    while(i<m&&j<n){
        if(arr[i]<nums2[j])
            nums1[count++]=arr[i++];
        else 
            nums1[count++]=nums2[j++];
        }
    if(i!=m){//判断nums1剩余还是nums2剩余
        for(;i<m;i++)
            nums1[count++]=arr[i];
    }else{
        for(;j<n;j++)
            nums1[count++]=nums2[j];
    }
}

27. 移除元素

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/remove-element/

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
int removeElement(int* nums, int numsSize, int val){
    int count=0;//count记录有效的数组数目
    for(int i=0;i<numsSize;i++){
        if(val!=nums[i]){
            nums[count++]=nums[i];
        }
    }
    return count;
}

链表

JZ76 删除链表中重复的结点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表 1->2->3->3->4->4->5 处理后为 1->2->5

/**
 * struct ListNode {
 *  int val;
 *  struct ListNode *next;
 * };
 */
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 *
 * @param pHead ListNode类
 * @return ListNode类
 */
  #include <stdlib.h>
struct ListNode* deleteDuplication(struct ListNode* pHead) {
      // write code here
    typedef struct ListNode ListNode;
    if(pHead==NULL||pHead->next==NULL)//空串则返回该头节点
        return pHead;
    ListNode* preHead=(ListNode*)malloc(sizeof(ListNode));
    preHead->next=pHead;
    ListNode* pre =preHead;//新链表的工作节点
    ListNode* cur=pHead;//遍历工作结点
    while (cur) {
        ListNode* nextDifferent=cur->next;
        while (nextDifferent&&nextDifferent->val==cur->val)//找到链表中两个不同节点 
            nextDifferent=nextDifferent->next;
        if(cur->next==nextDifferent){//如果链表没有中间的相同结点,那么就直接链接上
            pre->next=cur;
            pre=cur;
            cur=nextDifferent;
        }else {//如果中间有相同的中间结点,那么工作指针直接将这一段跳过
            cur=nextDifferent;
        }
    }
    pre->next=cur;
    return preHead->next;
  }

147. 对链表进行插入排序

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/insertion-sort-list

给定单个链表的头 head ,使用 插入排序 对链表进行排序,并返回 排序后链表的头 。

插入排序 算法的步骤:

插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
重复直到所有输入数据插入完为止。
下面是插入排序算法的一个图形示例。部分排序的列表(黑色)最初只包含列表中的第一个元素。每次迭代时,从输入数据中删除一个元素(红色),并就地插入已排序的列表中。

对链表进行插入排序。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* insertionSortList(struct ListNode* head){
    typedef struct ListNode ListNode;
    ListNode* dummy=(ListNode*)malloc(sizeof(ListNode));//返回的新链表
    dummy->next=NULL;
    ListNode* cur=head;
    while(cur){
        ListNode* prev=dummy;
        ListNode* next=cur->next;
        while(prev->next!=NULL&&prev->next->val <= cur->val){//边遍历 边比较
            prev=prev->next;
        }
        cur->next=prev->next;
        prev->next=cur;
        cur=next;
    }
    return dummy->next;
}

206. 反转链表

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/reverse-linked-list/description/

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* reverseList(struct ListNode* head){
    typedef struct ListNode ListNode;
    ListNode *p;
    p=(ListNode*)malloc(sizeof(ListNode));
    p->next=NULL;
    while(head!=NULL){
        ListNode* tmp=head;
        head=head->next;
        tmp->next=p->next;
        p->next=tmp;
    }
    head=p->next;
    free(p);
    return head;
}

876. 链表的中间结点

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/middle-of-the-linked-list/description/
给你单链表的头结点 head ,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* middleNode(struct ListNode* head){
    typedef struct ListNode ListNode;
    ListNode* p=head;
    int count=0;
    while(p!=NULL){
        p=p->next;
        ++count;
    }
    count=count/2;
    while(count>0){
        head=head->next;
        --count;
    }
    return head;
}

链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点。

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 */

/**
 * 
 * @param pListHead ListNode类 
 * @param k int整型 
 * @return ListNode类
 */
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    // write code here
    typedef struct ListNode ListNode;
    ListNode* p=pListHead;
    ListNode* q=pListHead;
    int count=k;
    while (count>0&&p!=NULL) {
        p=p->next;
        --count;
    }
    if(count>0&&p==NULL){
        q=p;
    }
    while (p!=NULL) {
        p=p->next;
        q=q->next;
    }
    return q;
}

21. 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    typedef struct ListNode ListNode;
    if(list1==NULL&&list2==NULL){
        return list1;
    }else if(list1==NULL&&list2!=NULL){
        return list2;
    }else if(list1!=NULL&&list2==NULL){
        return list1;
    }
    ListNode *p;
    p=(ListNode*)malloc(sizeof(ListNode));
    ListNode *q=p;
    while(list1!=NULL&&list2!=NULL){
        if(list1->val<list2->val){
            p->next=list1;
            p=p->next;
            list1=list1->next;
        }else{
            p->next=list2;
            p=p->next;
            list2=list2->next;
        }
    }
    while(list1!=NULL){
        p->next=list1;
        p=p->next;
        list1=list1->next;
    }
    while(list2!=NULL){
        p->next=list2;
        p=p->next;
        list2=list2->next;
    }
    return q->next;
}

203. 移除链表元素

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/remove-linked-list-elements/

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]
struct ListNode* removeElements(struct ListNode* head, int val){
    while(head!=NULL&&head->val==val){
        struct ListNode* tmp=head;
        head=head->next;
        free(tmp);
    }
    struct ListNode* cur=head;
    while(cur!=NULL&&cur->next!=NULL){
        if(cur->next->val==val){
             cur->next=cur->next->next;
        }else{
             cur=cur->next;
        }
    }
    return head;
}
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */


struct ListNode* removeElements(struct ListNode* head, int val){
    typedef struct ListNode ListNode;
    ListNode* dummyhead;
    dummyhead=(ListNode*)malloc(sizeof(ListNode));
    dummyhead->next=head;
    ListNode *cur=dummyhead;
    while(cur->next!=NULL){
        if(cur->next->val==val){
            ListNode* tmp=cur->next;
            cur->next=cur->next->next;
            free(tmp);
        }else{
            cur=cur->next;
        }
    }
    return dummyhead->next;
}

CM11 链表分割

来源:牛客网
链接:https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId=8&&tqId=11004&rp=2&ru=/activity/oj&qru=/ta/cracking-the-coding-interview/question-ranking

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
#include <cstddef>
#include <cstdlib>
class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        // write code here
         struct ListNode*head1,*head2,*tail1,*tail2;
         head1=tail1=(struct ListNode*)malloc(sizeof(struct ListNode));
         head2=tail2=(struct ListNode*)malloc(sizeof(struct ListNode));
         struct ListNode* cur=pHead;
        while (cur) {
            if(cur->val<x){
                tail1->next=cur;
                tail1=tail1->next;
            }else{
                tail2->next=cur;
                tail2=tail2->next;
            }
            cur=cur->next;
        }
        tail1->next=head2->next;
        tail2->next=NULL;
        pHead=head1->next;
        free(head1);
        free(head2);
        return pHead;
    }
};

OR36 链表的回文结构

https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId=49&&tqId=29370&rp=1&ru=/activity/oj&qru=/ta/2016test/question-ranking

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
测试样例

1->2->2->1
返回:true
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
#include <cstddef>
#include <cstdlib>
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        // write code here
        ListNode* dummy=(ListNode*)malloc(sizeof(ListNode));
        dummy->next=A;
        ListNode* fast=dummy;//快慢指针读取中间节点
        ListNode* slow=dummy;
        while (fast&&fast->next) {
        fast=fast->next->next;
        slow=slow->next;
        }
        ListNode* cur=slow->next;//工作指针
        ListNode* next=cur->next;//工作指针的下一个位置
        ListNode* pre=slow;//工作指针的上一个位置
        slow->next=NULL;//防止成环,断链
        while (1) {//将后半部分链表反转
            cur->next=pre;
            pre=cur;
            if (next==NULL)
                break;
            cur=next;
            next=cur->next; 
        }
        ListNode* head=A;
        ListNode* tail=cur;
        while (tail!=slow) {
            if(head->val!=tail->val)
                return false;
            tail=tail->next;
            head=head->next;
        }
        return true;
    }
};

160. 相交链表

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/intersection-of-two-linked-lists/

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    typedef struct ListNode ListNode;
    ListNode* p=headA;//p为工作指针,遍历两个链表并统计长度
    int countA=0,countB=0;
    while(p!=NULL){//统计headA的长度
        p=p->next;
        ++countA;
    }
    p=headB;
    while(p!=NULL){//统计headB的长度
        p=p->next;
        ++countB;
    }
    
    if(countA>countB){
        int len=countA-countB;
        p=headA;
        while(len){//将A链表到相同长度时
            p=p->next;
            --len;
        }
        while(p&&headB){//开始进行两链表的比对
            if(p==headB){
                return p;
            }
            p=p->next;
            headB=headB->next;
        }
    }else{
        int len=countB-countA;
        p=headB;
        while(len){//将B链表到相同长度时
            p=p->next;
            --len;
        }
        while(p&&headA){//开始进行两链表的比对
            if(p==headA){
                return p;
            }
            p=p->next;
            headA=headA->next;
        }        
    }
    return NULL;
}

141. 环形链表

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/linked-list-cycle

给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环 ,则返回 true 。 否则,返回 false 。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    typedef struct ListNode ListNode;
    ListNode* fast=head;
    ListNode* low=head;
    while(fast&&fast->next){//快指针先走,如果是有环那么该循环会永远退不出并最后追上;而fast->next==NULL就是while循环的出口
            fast=fast->next->next;
            low=low->next;
        if(fast==low)
            return true;
    }
    return false;
}

142. 环形链表 II

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/linked-list-cycle-ii

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。不允许修改链表。
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    typedef struct ListNode ListNode;
    ListNode* fast=head;
    ListNode* low=head;
    while(fast&&fast->next){//判断是否有环
        fast=fast->next->next;
        low=low->next;
        if(low==fast){//有环的话 根据距离公式推算 从当时相遇结点和头节点开始遍历 再次相遇就会是入环结点
            ListNode* p=fast;
            while(head&&p){
                if(head==p){
                    return p;
                }else{
                    head=head->next;
                    p=p->next;
                }
            }
        }
    }
    return NULL;
}

138. 复制带随机指针的链表

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/copy-list-with-random-pointer

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。
返回复制链表的头节点。
用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:
val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为 null 。
你的代码 只 接受原链表的头节点 head 作为传入参数。
在这里插入图片描述

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */

struct Node* copyRandomList(struct Node* head) {
	typedef struct Node Node;
    Node* cur=head;
    while(cur){//将结点全部复制一次并链接到该节点后面
        Node* copy=(Node*)malloc(sizeof(Node));//创建拷贝的结点
        copy->val=cur->val;//将拷贝结点放在当前结点的后面
        copy->next=cur->next;
        cur->next=copy;
        cur=copy->next;
    } 
    cur=head;//工作结点重新修正为原链表的头节点
    while(cur){//将节点中的random所指向的值进行复制
        if(cur->random==NULL)
            cur->next->random=NULL;
        else    
            cur->next->random=cur->random->next;
        cur=cur->next->next;
    }
    Node* copytail,*copyhead=(Node*)malloc(sizeof(Node));//创建拷贝结点链表的头和尾
    copyhead=copytail=NULL;
    cur=head;//工作结点重新修正为原链表的头节点
    while(cur){//将所拷贝的结点链接在一起,原本的结点不改变

        Node* next=cur->next->next;//next记录原链表的下一个结点的位置
        if(copytail==NULL){//如果拷贝结点最初为空时,
            copyhead=copytail=cur->next;
    }else{
            copytail->next=cur->next;
            copytail=copytail->next;
    }
           cur->next=next;
            cur=next;
    }
    return copyhead;
}

栈和队列

20. 有效的括号

给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/valid-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

typedef char STData;

typedef struct Stack{
    int capacity;//栈的容量
    int top;//栈顶位置
    STData* a;
}Stack;

void StackInit(Stack* s){//栈的初始化
    assert(s);
    s->a=NULL;
    s->capacity=0;
    s->top=0;
}

void StackDestroy(Stack* s){//栈销毁
    assert(s);
    free(s->a);
    s->a=NULL;
    s->capacity=0;
    s->top=0;
}

void StackPush(Stack* s,STData x){//将数据写入栈
    assert(s);
    if(s->top==s->capacity){
        int newCapacity = s->capacity == 0 ? 4 : s->capacity * 2;
        s->a=(STData*)realloc(s->a,sizeof(STData)*newCapacity);
        if(s->a==NULL){
            printf("realloc fail\n");
            exit(-1); 
        }
        s->capacity=newCapacity;
    }
    s->a[s->top]=x;
    s->top++;
}

void StackPop(Stack* s){//栈顶元素弹出栈
    assert(s);
    assert(s->top>0);
    --s->top;
}

STData StackTop(Stack* s){//取出栈顶元素
    assert(s);
    assert(s->top>0);
    return s->a[s->top-1];
}

bool StackEmpty(Stack* s){//判断栈是否为空
    assert(s);
    //printf("%d",s->top);
    return s->top==0;
}

bool isValid(char * s){
    Stack stack;
    StackInit(&stack);
    while(*s){
       if(*s=='('||*s=='{'||*s=='['){
           StackPush(&stack,*s);
           ++s;
       }else{
           if(StackEmpty(&stack)){
            return false;
           }
           STData top=StackTop(&stack);
           //printf("%d",stack.top);
           //printf("%c",top);
          // printf("%c\n",*s);
           StackPop(&stack);
           //printf("%d",stack.top);
           if(*s=='}'&&top!='{'
           ||*s==']'&&top!='['
           ||*s==')'&&top!='('){
               //StackDestroy(&s);
               return false;
           }else{
               ++s;
           }   
       }
    }
    
    bool ret =StackEmpty(&stack);
    StackDestroy(&stack);
    return ret;
}
char pairs(char a) {
    if (a == '}') return '{';
    if (a == ']') return '[';
    if (a == ')') return '(';
    return 0;
}

bool isValid(char* s) {
    int n = strlen(s);
    if (n % 2 == 1) {
        return false;
    }
    int stk[n + 1], top = 0;
    for (int i = 0; i < n; i++) {
        char ch = pairs(s[i]);
        if (ch) {
            if (top == 0 || stk[top - 1] != ch) {
                return false;
            }
            top--;
        } else {
            stk[top++] = s[i];
        }
    }
    return top == 0;
}

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/valid-parentheses/solution/you-xiao-de-gua-hao-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

225. 用队列实现栈

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/implement-stack-using-queues/

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、top、pop 和 empty)。

typedef int QDataType;
typedef struct QueueNode  //队列结点
{
	QDataType data;//结点数据类型
	struct QueueNode* next;//结点存储下一个结点的位置
}QNode;

typedef struct Queue//队列
{
	QNode* head;
	QNode* tail;
}Queue;

typedef struct {
    Queue q1;
    Queue q2;
} MyStack;

void QueueInit(Queue* pq)//队列初始化
{
	assert(pq);
	pq->head = pq->tail = NULL;
}

void QueueDestory(Queue* pq)//队列销毁
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
}

void QueuePush(Queue* pq, QDataType x)//进入队列
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	assert(newnode);

	newnode->data = x;
	newnode->next = NULL;

	if (pq->tail == NULL)
	{
		assert(pq->head == NULL);
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
}

void QueuePop(Queue* pq)//出队列
{
	assert(pq);
	assert(pq->head && pq->tail);

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

bool QueueEmpty(Queue* pq)//判断队列是否为空
{
	assert(pq);
	return pq->head == NULL;
}

size_t QueueSize(Queue* pq)//队列的长度
{
	assert(pq);
	QNode* cur = pq->head;
	size_t size = 0;
	while (cur)
	{
		size++;
		cur = cur->next;
	}

	return size;
}

QDataType QueueFront(Queue* pq)//获取队列的第一个元素
{
	assert(pq);
	assert(pq->head);

	return pq->head->data;
}

QDataType QueueBack(Queue* pq)//获取队列的尾元素
{
	assert(pq);
	assert(pq->tail);

	return pq->tail->data;
}

MyStack* myStackCreate() {
    MyStack* pst=(MyStack*)malloc(sizeof(MyStack));
    assert(pst);
    QueueInit(&pst->q1);
    QueueInit(&pst->q2);
    return pst; 
}

void myStackPush(MyStack* obj, int x) {
    assert(obj);
    if(!QueueEmpty(&obj->q1)){//如果q1不为空那么就为存放数据,反之q2存放数据
        QueuePush(&obj->q1,x);
    }else{
        QueuePush(&obj->q2,x);
    }
}

int myStackPop(MyStack* obj) {
    assert(obj);
    Queue* nonEmptyQ=&obj->q2;//先默认q2为空队列
    Queue* emptyQ=&obj->q1;//先默认q1为数据队列
    if(!QueueEmpty(&obj->q1)){//判断默认情况是否成立,不成立则交换
        emptyQ=&obj->q2;
        nonEmptyQ=&obj->q1;
    }
    while(QueueSize(nonEmptyQ)>1){//队列模拟栈出
        int front=QueueFront(nonEmptyQ);
        QueuePush(emptyQ,front);//一个队列进
        QueuePop(nonEmptyQ);//一个队列出
    }
    int top=QueueFront(nonEmptyQ);//在最后一个队列进入另一个队列时 返回当前值
    QueuePop(nonEmptyQ);
    return top;
}

int myStackTop(MyStack* obj) {
    assert(obj);
    if(!QueueEmpty(&obj->q1)){
        return QueueBack(&obj->q1);
    }else{
        return QueueBack(&obj->q2);
    }
}

bool myStackEmpty(MyStack* obj) {
    assert(obj);
    return QueueEmpty(&obj->q2)&&QueueEmpty(&obj->q1);
}

void myStackFree(MyStack* obj) {
    assert(obj);
    QueueDestory(&obj->q1);
    QueueDestory(&obj->q2);
    free(obj);
}


232. 用栈实现队列

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/implement-queue-using-stacks/

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):

typedef struct {
    int* stk;
    int stkSize;
    int stkCapacity;
} Stack;

Stack* stackCreate(int cpacity) {
    Stack* ret = malloc(sizeof(Stack));
    ret->stk = malloc(sizeof(int) * cpacity);
    ret->stkSize = 0;
    ret->stkCapacity = cpacity;
    return ret;
}

void stackPush(Stack* obj, int x) {
    obj->stk[obj->stkSize++] = x;
}

void stackPop(Stack* obj) {
    obj->stkSize--;
}

int stackTop(Stack* obj) {
    return obj->stk[obj->stkSize - 1];
}

bool stackEmpty(Stack* obj) {
    return obj->stkSize == 0;
}

void stackFree(Stack* obj) {
    free(obj->stk);
}

typedef struct {
    Stack* inStack;//一个只进
    Stack* outStack;//一个只出
} MyQueue;

MyQueue* myQueueCreate() {
    MyQueue* ret = malloc(sizeof(MyQueue));
    ret->inStack = stackCreate(100);//因为最多操作100次push、pop,所以容量申请为100
    ret->outStack = stackCreate(100);//同上
    return ret;
}

void in2out(MyQueue* obj) {
    while (!stackEmpty(obj->inStack)) {
        stackPush(obj->outStack, stackTop(obj->inStack));//一个栈进 一个栈出来模拟队列
        stackPop(obj->inStack);//最后将进栈的元素弹出
    }
}

void myQueuePush(MyQueue* obj, int x) {
    stackPush(obj->inStack, x);
}

int myQueuePop(MyQueue* obj) {
    if (stackEmpty(obj->outStack)) {
        in2out(obj);
    }
    int x = stackTop(obj->outStack);
    stackPop(obj->outStack);
    return x;
}

int myQueuePeek(MyQueue* obj) {
    if (stackEmpty(obj->outStack)) {
        in2out(obj);
    }
    return stackTop(obj->outStack);
}

bool myQueueEmpty(MyQueue* obj) {
    return stackEmpty(obj->inStack) && stackEmpty(obj->outStack);
}

void myQueueFree(MyQueue* obj) {
    stackFree(obj->inStack);
    stackFree(obj->outStack);
}


622. 设计循环队列

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/design-circular-queue/

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

typedef struct {
    int* a;
    int front;//记录队头下标
    int tail;//记录队尾下标
    int k;//队列长度
} MyCircularQueue;

bool myCircularQueueIsEmpty(MyCircularQueue* obj );
bool myCircularQueueIsFull(MyCircularQueue* obj);

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->a=(int*)malloc(sizeof(int)*(k+1));//申请k+1的空间 多一个空间是front和tail的循环
    obj->front=obj->tail=0;
    obj->k=k;//长度设为k
    return obj;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
        return false;
    obj->a[obj->tail]=value;
    if(obj->tail==obj->k){
        obj->tail=0;
    }else{
        obj->tail++;
    }
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))//分两种情况,如果front==k那么就到了队列的最后,再返回就是下标0绕回去
        return false;
    if(obj->front==obj->k){
        obj->front=0;
    }else{
        obj->front++;
    }
    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;
    if(obj->tail==0){//考虑到如果tail为0 那么最后一个元素在k位置上
        return obj->a[obj->k];
    }else{
        return obj->a[obj->tail-1];
    }
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front==obj->tail;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) {
    if(obj->tail==obj->k&&obj->front==0){
        return true;
    }else{
        return obj->tail+1==obj->front;
    }
}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->a);
    free(obj);
}

155. 最小栈

https://leetcode.cn/problems/min-stack/description/

class MinStack {
public:
    MinStack() {
        
    }
    
    void push(int val) {
        _st.push(val);
        if(_minst.empty()||_minst.top()>=val){
            _minst.push(val);
        }

    }
    
    void pop() {
        if(_minst.top()==_st.top()){
            _minst.pop();
        }
        _st.pop();
    }
    
    int top() {
        return _st.top();
    }
    
    int getMin() {
        return _minst.top();
    }

    private:
    stack<int> _st;
    stack<int> _minst;
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack* obj = new MinStack();
 * obj->push(val);
 * obj->pop();
 * int param_3 = obj->top();
 * int param_4 = obj->getMin();
 */

JZ31 栈的压入、弹出序列

https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106

#include<iostream>
using namespace std;
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param pushV int整型vector 
     * @param popV int整型vector 
     * @return bool布尔型
     */
    bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
        stack<int> st;
        int pushi=0,popi=0;
        while (pushi < pushV.size()) {
            st.push(pushV[pushi++]);
            while( !st.empty() && popV[popi]==st.top()){
                st.pop();
                popi++;
            }
        }
        return st.empty();
    }
};

150. 逆波兰表达式求值

https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
       for(auto& str:tokens) {//str一个一个取出字符串的字符和数字
           if(str=="+"||str=="*"||str=="/"||str=="-"){
               int right=st.top();
               st.pop();
               int left=st.top();
               st.pop();
               switch(str[0]){
                   case '+':
                        st.push(left+right);
                        break;
                    case '-':
                        st.push(left-right);
                        break;
                    case '*':
                        st.push(left*right);
                        break;
                    case '/':
                        st.push(left/right);
                        break;
               }
           }else{
               st.push(stoi(str));//stoi是string类型转integer类型
               
           }

       }
           return st.top();
    }
};

215. 数组中的第K个最大元素

https://leetcode.cn/problems/kth-largest-element-in-an-array/description/

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int> pq(nums.begin(),nums.end());

        while(k>1){
            pq.pop();
            --k;
        }
        
        return pq.top();
    }
};

965. 单值二叉树

https://leetcode.cn/problems/univalued-binary-tree/

如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。
只有给定的树是单值二叉树时,才返回 true;否则返回 false。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


bool isUnivalTree(struct TreeNode* root){
    if(root==NULL)
        return true;
    if(root->left!=NULL&&root->left->val!=root->val)
        return false;
    if(root->right!=NULL&&root->right->val!=root->val)
        return false;
    return isUnivalTree(root->left)&&isUnivalTree(root->right);
}

144. 二叉树的前序遍历

https://leetcode.cn/problems/binary-tree-preorder-traversal/

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int TreeHeight(struct TreeNode* root){//计算高度
    return root==NULL?0:TreeHeight(root->left)+TreeHeight(root->right)+1;
}

void _preorderTraversal(struct TreeNode* root,int *a,int *pi){//先序遍历 将不是NULL值传递给数组
    if(root==NULL)
        return;
    //printf("%d",*pi);
    a[(*pi)++]=root->val;
    _preorderTraversal(root->left,a,pi);
    _preorderTraversal(root->right,a,pi);
    return;
}

int* preorderTraversal(struct TreeNode* root, int* returnSize){
    int size=TreeHeight(root);
    //printf("size:%d\n",size);
    int *a=(int*)malloc(sizeof(int)*size);
    int i=0;
    _preorderTraversal(root,a,&i);
    *returnSize=size;
    return a;
}

94. 二叉树的中序遍历

https://leetcode.cn/problems/binary-tree-inorder-traversal/

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

int TreeSize(struct TreeNode* root){
    return root==NULL?0:TreeSize(root->right)+TreeSize(root->left)+1;
}

void _inorderTraversal(struct TreeNode* root,int* a,int *pi){
    if(root==NULL)
        return;
    if(root->left!=NULL||root->right!=NULL){
        _inorderTraversal(root->left,a,pi);
         a[(*pi)++]=root->val;
        _inorderTraversal(root->right,a,pi);
         return;
    }
    if(root->left==NULL&&root->left==NULL)
        a[(*pi)++]=root->val;
       
}

int* inorderTraversal(struct TreeNode* root, int* returnSize){
    typedef struct TreeNode TreeNode;
    int size=TreeSize(root);
    int i=0;
    //printf("%d",size);
    int *a=(int*)malloc(sizeof(int)*size);
    _inorderTraversal(root,a,&i);
    *returnSize=i;
    return a;
}

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

145. 二叉树的后序遍历

https://leetcode.cn/problems/binary-tree-postorder-traversal/

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


/**
 * Note: The returned array must be malloced, assume caller calls free().
 */

int TreeSize(struct TreeNode* root){
    return root==NULL?0:TreeSize(root->right)+TreeSize(root->left)+1;
}

void _postorderTraversal(struct TreeNode* root,int* a,int *pi){
    if(root==NULL)
        return;
    if(root->left!=NULL||root->right!=NULL){
        _postorderTraversal(root->left,a,pi);
        _postorderTraversal(root->right,a,pi);
         a[(*pi)++]=root->val;
         return;
    }
    if(root->left==NULL&&root->left==NULL)
        a[(*pi)++]=root->val;
       
}

int* postorderTraversal(struct TreeNode* root, int* returnSize){
    typedef struct TreeNode TreeNode;
    int size=TreeSize(root);
    int i=0;
    //printf("%d",size);
    int *a=(int*)malloc(sizeof(int)*size);
    _postorderTraversal(root,a,&i);
    *returnSize=i;
    return a;
}

100. 相同的树

https://leetcode.cn/problems/same-tree/

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


bool isSameTree(struct TreeNode* p, struct TreeNode* q){
    if(p==NULL&&q!=NULL)
        return false;
    if(p!=NULL&&q==NULL)
        return false;
    if(p==NULL&&q==NULL)
        return true;
    if(p->val!=q->val)
        return false;
    return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}

104. 二叉树的最大深度

给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


int maxDepth(struct TreeNode* root){
    return root==NULL?0:fmax(maxDepth(root->left),maxDepth(root->right))+1;
}

101. 对称二叉树

https://leetcode.cn/problems/symmetric-tree/

给你一个二叉树的根节点 root , 检查它是否轴对称。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

bool _isSymmetric(struct TreeNode* p,struct TreeNode* q){
    if(p==NULL&&q==NULL)
        return true;
    if(p==NULL||q==NULL)
        return false;
    if(p->val!=q->val)
        return false;
   return  _isSymmetric(p->right,q->left)&&_isSymmetric(p->left,q->right);
}

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

572. 另一棵树的子树

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/subtree-of-another-tree

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

bool isSameTree(struct TreeNode* p,struct TreeNode* q){
    if(p==NULL&&q==NULL)
        return true;
    if(p==NULL||q==NULL)
        return false;
    if(p->val!=q->val)
        return false;
    return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}

bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
    typedef struct TreeNode TreeNode;
    if(root==NULL)
        return false;
    if(isSameTree(root,subRoot))//先比较该节点是否相同 
        return true;
    return isSubtree(root->right,subRoot)||isSubtree(root->left,subRoot);//如果该节点的左右子树有一个能包含子树 那么返回就是true
}

110. 平衡二叉树

https://leetcode.cn/problems/balanced-binary-tree/

给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

int TreeHeight(struct TreeNode* root){
    if(root==NULL)
        return 0;
    int hl=TreeHeight(root->left)+1;
    int hr=TreeHeight(root->right)+1;
    if(hl>hr)
        return hl;
    return hr;
}

bool isBalanced(struct TreeNode* root){
    if(root==NULL)
        return true;
    //printf("left:%d   right:%d\n",TreeHeight(root->left),TreeHeight(root->right));
    if(abs(TreeHeight(root->left)-TreeHeight(root->right))>1)
        return false;
    return isBalanced(root->left)&&isBalanced(root->right);
}

KY11 二叉树遍历

https://www.nowcoder.com/practice/4b91205483694f449f94c179883c1fef?tpId=60&&tqId=29483&rp=1&ru=/activity/oj&qru=/ta/tsing-kaoyan/question-ranking

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

#include <stdio.h>
#include<stdlib.h>

typedef struct TreeNode{
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
}TreeNode;

TreeNode* CreateTree(char* str,int* pi){
    if(str[(*pi)]=='#'){
        (*pi)++;
        return NULL;
    }
    TreeNode *root=(TreeNode*)malloc(sizeof(TreeNode));
    root->val=str[(*pi)++];
    root->left=CreateTree(str,pi);
    root->right=CreateTree(str,pi);
    return root;
}

void InOrder(TreeNode *root){
    if(root==NULL)
        return;
    InOrder(root->left);
    printf("%c ",root->val);
    InOrder(root->right);
}

int main() {
    char str[100];
    int i=0;
    while (scanf("%s",str)!=EOF) {
        TreeNode *root=CreateTree(str, &i);
        InOrder(root);
    }
    return 0;
}

226. 翻转二叉树

https://leetcode.cn/problems/invert-binary-tree/

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */


struct TreeNode* invertTree(struct TreeNode* root){
    if(root==NULL)
        return root;
    if(root->left==NULL&&root->right==NULL){
        return root;
    }
    invertTree(root->left);
    invertTree(root->right);
    struct TreeNode* tmp=root->left;
    root->left=root->right;
    root->right=tmp;
    return root;
}

异或

面试题 17.04. 消失的数字

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/missing-number-lcci/

数组nums包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?
示例 1:

输入:[3,0,1]
输出:2

示例 2:

输入:[9,6,4,2,3,5,7,0,1]
输出:8
//原理:1^1=0 相同的数字异或会消失 所以原数组异或一次 再创造一组来全部异或一次
int missingNumber(int* nums, int numsSize){
    int sum=0;
    for(int i=0;i<numsSize;i++){
        sum^=nums[i];
    }
    for(int i=0;i<=numsSize;i++){
        sum^=i;
    }
    return sum;
}

剑指 Offer 56 - I. 数组中数字出现的次数

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/shu-zu-zhong-shu-zi-chu-xian-de-ci-shu-lcof/

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:

输入:nums = [4,1,4,6]
输出:[1,6][6,1]

示例 2:

输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10][10,2]
/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* singleNumbers(int* nums, int numsSize, int* returnSize){
    int sum=0;
    for(int i=0;i<numsSize;i++){
        sum^=nums[i];
    }
    int pos=sum&(-sum);//得到二进制位中的第pos位来分组
    int *rs=(int*)calloc(2,sizeof(int));
    for(int i=0;i<numsSize;i++){
        if(nums[i]&pos)
            rs[0]^=nums[i];
        else
            rs[1]^=nums[i];
    }
    *returnSize=2;
    return rs;
}

136.只出现一次的数字

https://leetcode.cn/problems/single-number/
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret =0;
        for(auto e:nums){
            ret ^=e;//ret与其他数字进行异或
        }
        return ret;
    }
};

字符串

HJ59 找出字符串中第一个只出现一次的字符

描述
找出字符串中第一个只出现一次的字符

数据范围:输入的字符串长度满足
1≤n≤1000

输入描述:
输入一个非空字符串

输出描述:
输出第一个只出现一次的字符,如果不存在输出-1

#include<iostream>

#include<string>

#include<list>

using namespace std;



int Hash(int key)

{

    return key - 'a';

}

int FirstTimeChar(string& str)

{

    int hashtable[26] = {0};

    //对字符串的每一个字符进行hash映射

    for (int i = 0; i < str.size(); ++i)

    {

        int index = Hash(str[i]);

        hashtable[index]++;

    }

    //按顺序检测每一个字符是否只出现一次

    for (int i = 0; i < str.size(); ++i)

    {

        int index = Hash(str[i]);

        if (hashtable[index] == 1)

            return str[i];

    }

    return -1;

}



int main()

{

    string str;

    while (getline(cin, str))

    {

        char res = FirstTimeChar(str);

        if (res == -1)

            cout << -1 << endl;

        else

            cout << res << endl;

    }

    return 0;

}

HJ1 字符串最后一个单词的长度

https://www.nowcoder.com/practice/8c949ea5f36f422594b306a2300315da?tpId=37&&tqId=21224&rp=5&ru=/activity/oj&qru=/ta/huawei/question-ranking
描述
计算字符串最后一个单词的长度,单词以空格隔开,字符串长度小于5000。(注:字符串末尾不以空格为结尾)
输入描述:
输入一行,代表要计算的字符串,非空,长度小于5000。

输出描述:
输出一个整数,表示输入字符串最后一个单词的长度。

#include <iostream>
using namespace std;

int main() {
    string str;
    getline(cin,str);
    //cout<<str<<endl;
    int pos=str.find_last_of(" ");
    //cout<<pos<<endl;
    str=str.substr(pos+1,str.size());
    //cout<<str<<endl;
    int size=str.size();
    cout<<str.size()<<endl;
    
}
// 64 位输出请用 printf("%lld")

387. 字符串中的第一个唯一字符

力扣:https://leetcode.cn/problems/first-unique-character-in-a-string/

给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1 。

class Solution {
public:
    int firstUniqChar(string s) {
        for(int i=0;i<s.size();i++){
            int index=s.find(s[i]);
            int reverse_index=s.rfind(s[i]);
            if(index==reverse_index)
                return i;
            }
        return -1;
    }
};

344. 反转字符串

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/reverse-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
public:
    void reverseString(vector<char>& s) {
        //cout<<s.size()<<endl;
        int left=0,right=s.size()-1;
        while(right>left){
            char temp=s[left];
            s[left]=s[right];
            s[right]=temp;
            right--;
            left++;
        }
    }
};

415. 字符串相加

给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。

你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/add-strings
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution 

{

public:

  //完成每一项的相加,进位可能会被修改,sign以引用传递

  int AddItem(int a, int b, int &sign)

  {

    int sum = a + b + sign;

    if(sum >= 10)

    {

      sum -= 10;

      sign = 1;

    }

    else

      sign = 0;

    return sum;

  }

  string addStrings(string num1, string num2) 

  {

    //先逆置数据,方便相加时有进位直接在数据的尾部插入即可,这样不会引起数据的移动

    reverse(num1.begin(), num1.end());

    reverse(num2.begin(), num2.end());

    int i, j, sign;

    i = j = sign = 0;

    int sum = 0;

    string res;

    while(i<num1.size() && j<num2.size())

    {

      sum = AddItem(num1[i]-'0', num2[j]-'0', sign);

      res.push_back(sum+'0');

      i++;

      j++;

    }



    while(i < num1.size())

    {

      sum = AddItem(num1[i]-'0', 0, sign);

      res.push_back(sum+'0');

      i++;

    }

    while(j < num2.size())

    {

      sum = AddItem(0, num2[j]-'0', sign);

      res.push_back(sum+'0');

      j++;

    }



    if(sign > 0)

    res.push_back(sign+'0');

    reverse(res.begin(), res.end());

    return res;

  }

};

把字符串转换成整数

牛客网:https://www.nowcoder.com/practice/1277c681251b4372bdef344468e4f26e?tpId=13&&tqId=11202&rp=6&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

描述
将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为 0 或者字符串不是一个合法的数值则返回 0
注意:
①字符串中可能出现任意符号,出现除 +/- 以外符号时直接输出 0
②字符串中可能出现 +/- 且仅可能出现在字符串首位。

class Solution {

  public:
  
    int StrToInt(string str)

    {

        int len = str.size();

        int flag = 1;

        if (len == 0)

            return 0;

        const char* cstr = str.c_str();

        if (cstr == NULL)

            return 0;

        int i = 0;

        if (cstr[i] == '+')

        {

            i++;

            flag = 1; //如果str[i]为'+',str[i]顺序后移,并令标志flag为1,表示为正数

        }

        else if (cstr[i] == '-')

        {

            i++;

            flag = -1; //如果str[i]为'-',str[i]顺序后移,并令标志flag为-1,表示为负数

        }

        long long num = 0;

        while (cstr[i] != '\0')

        {

            if (cstr[i] >= '0' && cstr[i] <= '9')

            {

                //每遍历一个在0-9间的字符,就将其输入到num中

                num = num * 10 + (cstr[i] -
                                  '0'); //下一次输入到num中时要加上上一次*10的结果,即上一次的数左移一位(十进制下)



                //如果数据溢出,则返回0

                if ((flag > 0 && num > 0x7fffffff) || (flag < 0 && num > 0x80000000))

                    return 0;

                i++;

            }

            else

            {

                return 0;

            }

        }

        if (flag < 0)

            num = num * -1;

        return (int)num;

    }

};

43. 字符串相乘

给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。

注意:不能使用任何内置的 BigInteger 库或直接将输入转换为整数。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/multiply-strings
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
public:
    string multiply(string num1, string num2) {
       if(num1=="0"||num2=="0") 
        return "0";
        int m=num1.size(),n=num2.size();
        auto ansArr = vector<int>(m+n);
        for (int i = m - 1; i >= 0; i--) {
            int x = num1.at(i) - '0';
            for (int j = n - 1; j >= 0; j--) {
                int y = num2.at(j) - '0';
                ansArr[i + j + 1] += x * y;
            }
        }
        for(int i=m+n-1;i>0;i--){
            ansArr[i-1]+=ansArr[i]/10;
            ansArr[i]%=10;
        }
        int index=ansArr[0]==0?1:0;
        string ans;
        while(index<m+n){
            ans.push_back(ansArr[index]);
            index++;
        }
        for(auto &c:ans){
            c+='0';
        }
        return ans;
    }
};

557. 反转字符串中的单词 III

力扣:https://leetcode.cn/problems/reverse-words-in-a-string-iii/
给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

class Solution {
public:
    void reverse(string &s,int begin,int end){
        char temp;
        while(begin<end){
            temp=s.at(begin);
            s[begin]=s[end];
            s[end]=temp;
            begin++;
            end--;
        }
    }
    string reverseWords(string s) {
        int begin=0,end=0;
        while(s.size()>begin){
            end=s.find(' ',begin);//从字符串begin的位置开始搜索空格
            //cout<<s<<endl;
            if(end==string::npos){
                end=s.size();
                break;
            }
            reverse(s,begin,end-1);
            begin=end+1;
        }
        reverse(s,begin,end-1);
        return s;
    }
};

541. 反转字符串 II

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/reverse-string-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
public:
    void reverse(string &s,int begin,int end){
        char temp;
        while(begin<end){
            temp=s[begin];
            s[begin]=s[end];
            s[end]=temp;
            begin++;
            end--;
        }
    }
    string reverseStr(string s, int k) {
        for(int i=0;i<s.size();i=i+(2*k)){
            if(i+k<s.size()){
                reverse(s,i,i+k-1);
                continue;
            }
            reverse(s,i,s.size()-1);
        }
        return s;
    }
};

125. 验证回文串

如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。

字母和数字都属于字母数字字符。

给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/valid-palindrome
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

class Solution {
public:
    bool isPalindrome(string s) {
        string sgood;
        for(char ch:s){
            if(isalnum(ch)){
                sgood+=tolower(ch);
            }
        }
        int begin=0,end=sgood.size()-1;
        //cout<<begin<<endl;
        //cout<<end<<endl;
        while(begin<end){
            if(sgood[begin++]!=sgood[end--])
                return false;
        }
        return true;
    }
};

917 仅仅反转字母

https://leetcode.cn/problems/reverse-only-letters/description/
给你一个字符串 s ,根据下述规则反转字符串:

所有非英文字母保留在原有位置。
所有英文字母(小写或大写)位置反转。
返回反转后的 s 。

#include <cctype>
class Solution {
public: 
    string reverseOnlyLetters(string s) {
        size_t begin=0,end=s.size()-1;
        //cout<<end;
        while(end>begin){
        while(begin<end&&!isalpha(s[begin]))
        begin++;
        while(end>begin&&!isalpha(s[end]))
        end--;
        swap(s[begin],s[end]);
        begin++;
        end--;
        }
        return s;
    }
};

其他

KY258 日期累加

https://www.nowcoder.com/practice/eebb2983b7bf40408a1360efb33f9e5d?tpId=40&&tqId=31013&rp=1&ru=/activity/oj&qru=/ta/kaoyan/question-ranking
描述
设计一个程序能计算一个日期加上若干天后是什么日期。
输入描述:
输入第一行表示样例个数m,接下来m行每行四个整数分别表示年月日和累加的天数。
输出描述:
输出m行,每行按yyyy-mm-dd的个数输出。

1
2008 2 3 100
2008-05-13

代码:

#include <iostream>
using namespace std;

//天数建立数组
int daytab[2][13]={
    {0,31,28,31,30,31,30,31,31,30,31,30,31},
    {0,31,29,31,30,31,30,31,31,30,31,30,31}
};
//是否是闰年
bool IsLeapYear(int year){
    return (year%4==0&&year%100!=0)||(year%400==0);
}
//判断这一年有多少天
int Numberofyear(int year){
    if(IsLeapYear(year))
        return 366;
    return 365;
}

int main() {
    int m,year,month,day,number;
    cin>>m;
    while (m--) {
        while (cin>>year>>month>>day>>number) {
            int row=IsLeapYear(year);
            for(int i=0;i<month;++i){
                number+=daytab[row][i];
            }
            number+=day;
            while (number>Numberofyear(year)) {
                number-=Numberofyear(year);
                year++;
            }
            month=0;
            row=IsLeapYear(year);
            while (number>daytab[row][month]) {
                number-=daytab[row][month];
                month++;
            }
            day=number;
            //cout<<year<<"-"<<month<<"-"<<day;
            printf("%04d-%02d-%02d\n",year,month,day);
        }
    }
}

KY222 打印日期

https://www.nowcoder.com/practice/b1f7a77416194fd3abd63737cdfcf82b?tpId=69&&tqId=29669&rp=1&ru=/activity/oj&qru=/ta/hust-kaoyan/question-ranking
描述
给出年分m和一年中的第n天,算出第n天是几月几号。
输入描述:
输入包括两个整数y(1<=y<=3000),n(1<=n<=366)。
输出描述:
可能有多组测试数据,对于每组数据, 按 yyyy-mm-dd的格式将输入中对应的日期打印出来。

输入:
2000 3
2000 31
2000 40
2000 60
2000 61
2001 60

输出:
2000-01-03
2000-01-31
2000-02-09
2000-02-29
2000-03-01
2001-03-01
#include <iostream>
using namespace std;

int main() {
    int year, day;
    int mon[13]={31, 28, 31, 30, 31, 30, 31, 31, 30 ,31, 30, 31};
    while (cin >> year >> day) { // 注意 while 处理多个 case
       if((year%4==0)&&(year%100!=0)||(year%400==0)){
        mon[1]=29;
       } else{
        mon[1]=28;
       }
       for(int i=0;i<12;i++){
        if(day<mon[i]){
            printf("%4d-%02d-%02d\n",year,i+1,day);
            break;
        }else{
            day-=mon[i];
        }
       }
    }
    return 0;
}
// 64 位输出请用 printf("%lld")

KY111 日期差值

https://www.nowcoder.com/practice/ccb7383c76fc48d2bbc27a2a6319631c?tpId=62&&tqId=29468&rp=1&ru=
描述
有两个日期,求两个日期之间的天数,如果两个日期是连续的我们规定他们之间的天数为两天
输入描述:
有多组数据,每组数据有两行,分别表示两个日期,形式为YYYYMMDD
输出描述:
每组数据输出一行,即日期差值

输入:
20110412
20110422

输出:
11
#include <iostream>
using namespace std;

int mon[12]={0,31,59,90,120,151,181,212,243,273,304,334};

int CountDay(int year,int month,int day){
    int yearDay=year*365+year/4-year/100+year/400;
    int monthDay=mon[month-1];
    if(month>2&&((year/4==0)&&(year/100!=0)&&(year/400==0)))
        monthDay+=1;
    return yearDay+monthDay+day;
}

int main() {
    int year1, month1, day1;
    int year2, month2, day2;
    scanf("%4d%2d%2d",&year1,&month1,&day1);
    int n1 = CountDay(year1,month1,day1);
    scanf("%4d%2d%2d",&year2,&month2,&day2);
    int n2 = CountDay(year2,month2,day2);
    cout<<abs(n1-n2)+1<<endl;
}

在这里插入图片描述

HJ73 计算日期到天数转换

https://www.nowcoder.com/practice/769d45d455fe40b385ba32f97e7bcded?tpId=37&&tqId=21296&rp=1&ru=/activity/oj&qru=/ta/huawei/question-ranking
描述
根据输入的日期,计算是这一年的第几天。
保证年份为4位数且日期合法。
进阶:时间复杂度:O(n) ,空间复杂度:O(1)
输入描述:
输入一行,每行空格分割,分别是年,月,日

输出描述:
输出是这一年的第几天

输入:
2012 12 31

输出:
366

输入:
1982 3 4

输出:
63
#include <iostream>
using namespace std;

int main() {
    int year,month,day;
    cin>>year>>month>>day;
    //cout<<year<<month<<day;
    int monthDays[13]={0,31,59,90,120,151,181,212,243,273,304,334,365};
    int n = monthDays[month-1]+day;
    if (month>2&&(((year%4==0)&&(year%100!=0))||year%400==0)){
        n+=1;
    } 
    cout<<n<<endl;
    return 0;
}

JZ64 求1+2+3+…+n

https://www.nowcoder.com/practice/7a0da8fc483247ff8800059e12d7caf1?tpId=13&tqId=11200&tPage=3&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
描述
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

class Solution {
public:
    int Sum_Solution(int n) {
        if(n==1) return 1;
        else 
            return n+Sum_Solution(n-1);
    }
};
class Sum{
public:
    Sum(){
        Sum::sum+=count;
        Sum::count++;
    }

    static int getSum(){
        return sum;
    }
    
private:
    static int  sum;
    static int count;
};

int Sum:: sum=0;
int Sum:: count=1;

class Solution {
public:
    int Sum_Solution(int n) {
        Sum a[n];
        return Sum::getSum();
    }
};

118. 杨辉三角

https://leetcode.cn/problems/pascals-triangle/description/

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> vv;
        vv.resize(numRows,vector<int>());
        for(size_t i=0;i<vv.size();++i){
            vv[i].resize(i+1,0);
            vv[i][0]=vv[i][vv[i].size()-1]=1;
        }

        for(size_t i=0;i<vv.size();++i){
            for(size_t j=0;j<vv[i].size();++j){
                if(vv[i][j]==0){
                    vv[i][j]=vv[i-1][j]+vv[i-1][j-1];
                }
            }
        }

        return vv;
    }
};

17. 电话号码的字母组合

https://leetcode.cn/problems/letter-combinations-of-a-phone-number/description/

class Solution {
    string _numToStr[10]={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
public:
    void combination(const string& digits,size_t di,string combinationstr,vector<string>& strV){
        if(di==digits.size()){//判断在第几层
            strV.push_back(combinationstr);
            return;
        }
        int num = digits[di]-'0';//判断该数的数字大小
        string str=_numToStr[num];//转换为字符串
        for(auto ch:str){
            combination(digits,di+1,combinationstr+ch,strV);//遍历该数字所对应的字符串并递归调用
        }
    }
    vector<string> letterCombinations(string digits) {
        vector<string> strV;
        if(digits=="")
            return strV;
        combination(digits,0,"",strV);
        return strV;
    }
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值