一、链表
1、两数相加
算法思想:
1、设置两个指针p,q,分别指向两个链表的头结点
2、设置一个临时变量temp,用来记录两个数相加时是否有进位,初始化为0。只要p,q指针不指向空,就循环把两个指针所指向节点的值和temp相加。如果大于9,就让一个临时变量设置为1,并把相加结果减10,把结果赋给两个指针所指向节点的值;如果小于9就直接赋值给两个节点所指向的值。然后p,q指针分别后移一个节点。
3、最后,判断两个链表哪个更长,如果一样长,直接返回其中一个链表。如果不一样长,再判断一次进位,把临时变量加给哪个长的链表所对应节点,返回长的链表的头结点。
struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
struct ListNode *p=l1,*q=l2;
int temp=0;
while(p!=NULL&&q!=NULL){
p->val+=temp;
temp=0;
p->val=p->val+q->val;
if(p->val>9){
p->val-=10;
temp++;
}
q->val=p->val;
p=p->next;
q=q->next;
}
if(q==NULL&&p==NULL){
return l1;
}
else if(q==NULL){
p->val+=temp;
return l1;
}
else{
q->val+=temp;
return l2;
}
}
2、删除链表的倒数第 N 个结点
算法思想:
1、使用双指针的思想,设置头指针p和尾指针q,初始时都指针链表头结点。先让q指针后移n个位置。
2、同时向后移动p,q指针,直到q指针到达最后一个结点,这样p指针就指向了倒数第n个结点,同时设置t指针指向p指针前面一个位置,方便删除操作。
3、把t指针指向p指针的下一个指针,这样就完成了删除操作,返回链表节点。
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
if(head->next==NULL){
return NULL;
}
struct ListNode *p=head,*q=head,*t=head;
while(--n){
q=q->next;
}
while(q->next!=NULL){
q=q->next;
t=p;
p=p->next;
}
t->next=p->next;
return head;
}
3、合并两个有序链表
算法思想:
1、新建一个头指针,作为一个新的有序链表的头结点。设置p,q指针分别指向两个链表的头结点。
2、循环移动p,q指针,直到p,q指针有指向空结点才停止。比较p,q指针所指向结点值的大小,把小的结点加到新的链表后面。
3、判断哪个链表还有剩余结点,直接把这些剩余结点都加到新的链表后面,返回新链表的头指针,。
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode *p=list1,*q=list2,*r;
struct ListNode *x = (struct ListNode*)malloc(sizeof(struct ListNode));
r=x;
x->next=NULL;
while(p!=NULL&&q!=NULL){
if(p->val<q->val){
r->next=p;
p=p->next;
}
else{
r->next=q;
q=q->next;
}
r=r->next;
}
if(p!=NULL){
r->next=p;
}
else{
r->next=q;
}
return x->next;
}
4、两两交换链表中的节点
算法思想:
1、设置一个哑指针指向头结点,方便后续操作,设置一个移动指针p,哑指针指向p
2、循环判断p的下一个结点和下两个结点是否为空,不为空的话,就交换两个结点的位置,并把移动指针指向交换后的后面那个指针。
3、直到p下一个指针或下两个指针为空,说明交换结束,返回头指针,即哑指针的下一个结点。
struct ListNode* swapPairs(struct ListNode* head){
struct ListNode *r= (struct ListNode*)malloc(sizeof(struct ListNode));
r->next = head;
struct ListNode* p = r;
while (p->next != NULL && p->next->next != NULL) {
struct ListNode* node1 = p->next;
struct ListNode* node2 = p->next->next;
p->next = node2;
node1->next = node2->next;
node2->next = node1;
p = node1;
}
return r->next;
}
5、旋转链表
算法思想:
1、使用双指针的思想,设置p,q指针指向头结点。同时遍历一遍链表,得到链表的长度len
2、因为k如果大于len的值,说明整体重复移动了超过一遍,所以可以对k取余,保证整体移动少于一次。把q指针先后移k%len个位置,然后同时移动p,q,当q指针指向最后一个结点时,p指针指向倒数第k个结点
3、记录p指针的下一个指针,因为这是旋转后的头结点,把p指针指向结点和下一个结点断开,同时把尾指针和头指针相连,这样就完成了链表的旋转。
struct ListNode* rotateRight(struct ListNode* head, int k){
struct ListNode *p=head,*q=head;
if(p==NULL){
return head;
}
int len=1;
while(p->next!=NULL){
p=p->next;
len++;
}
p=head;
k=k%len;
while(k-->0){
q=q->next;
}
while(q->next!=NULL){
q=q->next;
p=p->next;
}
q->next=head;
q=p->next;
p->next=NULL;
return q;
}
6、 删除排序链表中的重复元素 II
算法思想:
1、设置一个哑指针指向头结点,方便后续操作,设置一个移动指针p,哑指针指向p,判断链表长度是否小于2,如果小于2,就说明肯定没有重复元素,直接返回头结点
2、循环判断p指针的后两个结点是否为空,如果不为空,判断这连个结点的值是否相等。如果相等,记录下这个值,并循环判断p后面的结点是否等于这个值,只要相等就删除。如果不相等,后移p指针
3、返回哑结点的后一个结点
struct ListNode* deleteDuplicates(struct ListNode* head){
ListNode *r=(struct ListNode*)malloc(sizeof(struct ListNode));
r->next=head;
if(head==NULL||head->next==NULL){
return head;
}
struct ListNode *p=r;
while(p->next!=NULL&&p->next->next!=NULL){
if(p->next->val==p->next->next->val){
int x=p->next->val;
while(p->next!=NULL&&p->next->val==x){
p->next=p->next->next;
}
}
else{
p=p->next;
}
}
return r->next;
}
7、分隔链表
算法思想:
1、建立两个哑指针left和right分别来维护比x小的结点和大于等于x的结点
2、设置移动指针p初始指向头结点,只要p指针不为空,循环判断p指针对应结点的值,如果小于x,就加入到left链表中,否则加入到right链表,同时后移p指针。
3、把right链表加入到left链表队尾,把right队尾置空,返回left的头指针
struct ListNode* partition(struct ListNode* head, int x){
struct ListNode* left=(struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* right=(struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode *p=head,*l=left,*r=right;
while(p!=NULL){
if(p->val<x){
l->next=p;
l=l->next;
}
else{
r->next=p;
r=r->next;
}
p=p->next;
}
r->next=NULL;
l->next=right->next;
return left->next;
}
8、反转链表
算法思想:
使用头插法
struct ListNode* reverseList(struct ListNode* head){
struct ListNode *dummy=(struct ListNode*)malloc(sizeof(struct ListNode));
dummy->next=NULL;
if(!head){
return head;
}
struct ListNode *p=head,*r=dummy,*q=head->next;
while(p){
q=p->next;
p->next=r->next;
r->next=p;
p=q;
}
return dummy->next;
}
9、环形链表 II
算法思想:
设置快慢指针p,q,如果有环的话,p和q会相遇,如果没有环的话,p,q指向空结点就结束
算法思想:
寻找链表中点 + 链表逆序 + 合并链表
11、对链表进行插入排序
算法思想:
1、维护一个有序序列,初始时创建一个哑结点,指向头结点,再设置一个指针q指向头结点后一个结点,断开头结点与后面的结点。这样就构成了两个链表,其中前面哑指针指向的链表是有序的。
2、为了防止断链,设置一个r指针指向q指针后面一个位置。然后拿着q指针指向结点的值,去遍历前面这个有序链表,找到合适的位置插入进去。
3、把q指针指向r指针指向的位置,r再指向q后面的一个位置,循环往复去插入,直到后面这个链表所有指针都被插入到有序链表中。
struct ListNode* insertionSortList(struct ListNode* head){
if(!head||!head->next){
return head;
}
struct ListNode *t=(struct ListNode*)malloc(sizeof(struct ListNode));
t->next=head;
struct ListNode *p=t,*q=head->next,*r;
head->next=NULL;
while(q){
r=q->next;
while(p->next&&q->val>p->next->val){
p=p->next;
}
q->next=p->next;
p->next=q;
p=t;
q=r;
}
return t->next;
}
12、相交链表
算法思想
1、设置移动指针p,q分别指向两个头结点,同时遍历两个链表得到链表长度
2、选择链表较长的那个链表,后移指针至剩余链表长度与另一个链表长度相同的位置
3、同时后移p,q指针,循环比较是否移动到了相同结点,如果到循环结束都未能移动到相同结点,说明不存在相交节点
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
struct ListNode *p=headA,*q=headB;
int len1=0,len2=0;
while(p){
len1++;
p=p->next;
}
while(q){
len2++;
q=q->next;
}
p=headA;
q=headB;
if(len1>len2){
int x=len1-len2;
while(x--){
p=p->next;
}
}
if(len2>len1){
int x=len2-len1;
while(x--){
q=q->next;
}
}
while(p&&q){
if(p==q){
return p;
}
p=p->next;
q=q->next;
}
return NULL;
}
13、移除链表元素
算法思想:
1、设置一个哑结点,指向头结点,再设置移动结点p,q指向头结点和头结点后一个结点;
2、只要q结点不为空,就循环判断p指向的结点是否等于给定值val,如果相等,则把p结点指向q结点的后一个结点,并且后移q结点;如果不等,后移p,q结点
3、返回哑结点的后一个结点
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* newhead=(struct ListNode*)malloc(sizeof(struct ListNode));
newhead->next=head;
struct ListNode* p=newhead,*q=head;
while(q){
if(q->val==val){
p->next=q->next;
}
else{
p=p->next;
}
q=q->next;
}
return newhead->next;
}
14、回文链表
算法思想:
把链表的值赋值到数组中,然后遍历链表判断是否回文
bool isPalindrome(struct ListNode* head){
int arr[100000];
int len=0;
while(head){
arr[len++]=head->val;
head=head->next;
}
for(int i=0;i<len/2;i++){
if(arr[i]!=arr[len-i-1]){
return false;
}
}
return true;
}
15、 删除链表中的节点
这题思想巧妙
算法思想:
把给定结点下一个结点的值赋给给定结点,然后删除下一个结点
void deleteNode(struct ListNode* node) {
struct ListNode* p=node->next;
node->val=p->val;
node->next=p->next;
}
16、奇偶链表
算法思想:
1、设置一个偶数结点的头结点,用于存放所有的偶数索引
2、遍历链表,把每个偶数结点放入偶数链表
3、剩下的结点都是奇数索引结点,把偶数链表拼接到奇数链表最后
struct ListNode* oddEvenList(struct ListNode* head){
if(!head||!head->next)return head;
struct ListNode *odd=(struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* p=head,*q=head->next,*r=odd;
while(p->next&&p->next->next){
q=p->next;
p->next=p->next->next;
r->next=q;
r=r->next;
p=p->next;
}
if(p->next){
r->next=p->next;
r=r->next;
}
p->next=odd->next;
r->next=NULL;
return head;
}
17、链表的中间结点
算法思想:
使用快慢指针,快的指针走两部,慢的指针走一步,这样当快指针到链尾,慢指针走到中间位置
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* p=head,*q=head;
while(q->next&&q->next->next){
p=p->next;
q=q->next->next;
}
if(q->next){
return p->next;
}
return p;
}
二、二叉树
void fun(struct TreeNode* root,int* arr,int* returnSize){
if(root==NULL){
return;
}
fun(root->left,arr,returnSize);
arr[(*returnSize)++]=root->val;
fun(root->right,arr,returnSize);
return;
}
int* inorderTraversal(struct TreeNode* root, int* returnSize){
int* res = (int*)malloc(sizeof(int) * 501);
*returnSize=0;
fun(root,res,returnSize);
return res;
}
bool fun(struct TreeNode* root,long min,long max){
if(!root){
return true;
}
if(root->val<=min||root->val>=max){
return false;
}
return fun(root->left,min,root->val)&&fun(root->right,root->val,max);
}
bool isValidBST(struct TreeNode* root){
return fun(root,-10000000000,10000000000);
}
bool isSameTree(struct TreeNode* p, struct TreeNode* q){
if(!p&&!q){
return true;
}else if(!p||!q){
return false;
}else if(p->val!=q->val){
return false;
}else{
return isSameTree(p->left,q->left)&&isSameTree(p->right,q->right);
}
}
bool fun(struct TreeNode* p, struct TreeNode* q){
if(!p&&!q){
return true;
}else if(!p||!q){
return false;
}else if(p->val!=q->val){
return false;
}else{
return fun(p->left,q->right)&&fun(p->right,q->left);
}
}
bool isSymmetric(struct TreeNode* root){
struct TreeNode* p=root,*q=root;
return fun(p,q);
}
void fun(struct TreeNode* root,int high,int* height){
if(!root){
return;
}
high++;
fun(root->left,high,height);
fun(root->right,high,height);
if(high>*height){
*height=high;
}
return;
}
int maxDepth(struct TreeNode* root){
int height=0;
fun(root,0,&height);
return height;
}
int height(struct TreeNode* root) {
if (root == NULL) {
return 0;
} else {
return fmax(height(root->left), height(root->right)) + 1;
}
}
bool isBalanced(struct TreeNode* root) {
if (root == NULL) {
return true;
} else {
return fabs(height(root->left) - height(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right);
}
}
int minDepth(struct TreeNode* root){
if(!root)return 0;
int height=100000;
fun(root,0,&height);
return height;
}
void fun(struct TreeNode* root,int high,int* height){
if(!root){
return;
}
high++;
fun(root->left,high,height);
fun(root->right,high,height);
if(high<*height&&!root->left&&!root->right){
*height=high;
}
return;
}
void fun(struct TreeNode* root,int targetSum,int num,int* sign){
if(!root){
return;
}
num+=root->val;
if(num==targetSum&&!root->left&&!root->right){
*sign=1;
}
fun(root->left,targetSum,num,sign);
fun(root->right,targetSum,num,sign);
return;
}
bool hasPathSum(struct TreeNode* root, int targetSum){
if(!root)return false;
int sign=0;
fun(root,targetSum,0,&sign);
if(sign==1){
return true;
}else{
return false;
}
}
void fun(struct TreeNode* root,int* height,int h){
if(!root){
return;
}
h=h*10+root->val;
if(!root->left&&!root->right){
*height+=h;
return;
}
fun(root->left,height,h);
fun(root->right,height,h);
return;
}
int sumNumbers(struct TreeNode* root){
int height=0;
if(!root)return 0;
fun(root,&height,0);
return height;
}
struct TreeNode* invertTree(struct TreeNode* root){
if(!root){
return NULL;
}
struct TreeNode *left=invertTree(root->left);
struct TreeNode *right=invertTree(root->right);
root->left=right;
root->right=left;
return root;
}
11、二叉搜索树中第K小的元素
12、二叉搜索树的最近公共祖先
12、二叉树的最近公共祖先
14、左叶子之和
void fun(struct TreeNode* root,int* returnSize){
if(!root){
return;
}
if(root->left&&!root->left->left&&!root->left->right){
*returnSize+=root->left->val;
}
fun(root->left,returnSize);
fun(root->right,returnSize);
return;
}
int sumOfLeftLeaves(struct TreeNode* root){
int returnSize=0;
fun(root,&returnSize);
return returnSize;
}
void fun(struct TreeNode* root,int* returnSize,int high,int* height){
if(!root){
return;
}
high++;
fun(root->left,returnSize,high,height);
fun(root->right,returnSize,high,height);
if(high>*height){
*height=high;
*returnSize=root->val;
}
return;
}
int findBottomLeftValue(struct TreeNode* root){
int returnSize=root->val;
int height=0;
fun(root,&returnSize,0,&height);
return returnSize;
}
17、把二叉搜索树转换为累加树
18、二叉树的直径
19、合并二叉树
20、二叉搜索树中的搜索
struct TreeNode* searchBST(struct TreeNode* root, int val){
while(root){
if(root->val==val){
return root;
}
else if(root->val>val){
root=root->left;
}
else{
root=root->right;
}
}
return NULL;
}