文章目录
-
- 一、数组
-
- 1.数组循环左移:408考研10年42题
- [2.搜索旋转数组 (面试题)](#2.搜索旋转数组 (面试题))
- 3.169.多数元素
- 4.191.1的个数
- 二、链表
-
- 1.876.链表的中间结点
- 2.141.环形链表
- [3.206.反转链表、LCR 024.反转链表](#3.206.反转链表、LCR 024.反转链表)
- 4.21.合并两个有序链表
- [5.61.旋转链表 【待做,Linux01】](#5.61.旋转链表 【待做,Linux01】)
- 三、递归
- 四、排序
- 五、二叉树
- 六、查找
-
- [1.寻找旋转排序数组中的最小值 (待做,Linux02)](#1.寻找旋转排序数组中的最小值 (待做,Linux02))
- [2.275.H指数 (二分查找)](#2.275.H指数 (二分查找))
- 七、STL容器
Leetcode:
①锻炼写代码的基本能力
②锻炼算法能力

一、数组
1.数组循环左移:408考研10年42题

思路:Reverse()函数
c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void print_array(int arr[], int n) {
for (int i = 0; i < n; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
void reverse(int arr[], int left, int right) {
while (left < right) {
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}
void rotateLeft(int arr[], int n, int k) {
k = k % n;
if (k == 0) return;
reverse(arr, 0, k - 1);
reverse(arr, k, n - 1);
reverse(arr, 0, n - 1);
}
int main() {
int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
rotateLeft(arr, 10, 5);
print_array(arr, 10);
return 0;
}
2.搜索旋转数组 (面试题)
链接:https://leetcode.cn/problems/search-rotate-array-lcci/description/
3.169.多数元素
4.191.1的个数
二、链表
1.876.链表的中间结点
链接:https://leetcode.cn/problems/middle-of-the-linked-list/
思路1:求链表中间结点:两次遍历
c
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* middleNode(struct ListNode* head) {
int count = 0;
struct ListNode* current = head;
while (current != NULL) {
current = current->next;
count++;
}
int mid = count / 2;
current = head;
for (int i = 0; i < mid; i++) {
current = current->next;
}
return current;
}
思路2:快慢指针 (效率高)
c
struct ListNode* middleNode(struct ListNode* head) {
struct ListNode* fast = head;
struct ListNode* slow = head;
while (fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
}
return slow;
}
完整代码
c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node {
int data;
struct node* next;
} Node;
Node* node_create(void) {
return calloc(1, sizeof(Node));
}
void node_destroy(Node* head) {
Node* cur = head;
while (cur != NULL) {
Node* next = cur->next;
free(cur);
cur = next;
}
}
//头插法
void add_before_head(Node** head, int value) {
Node* new_node = malloc(sizeof(Node));
new_node->data = value;
new_node->next = *head;
*head = new_node;
}
//1.求链表中间结点:两次遍历
int middleElement(Node* list) { //Node* list是指向链表头节点的指针
int count = 0;
Node* current = list;
while (current != NULL) {
current = current->next;
count++;
}
int mid = count / 2;
current = list;
for (int i = 0; i < mid; i++) {
current = current->next;
}
return current->data;
}
void print_list(Node* head) {
while (head != NULL) {
printf("%d ", head->data);
head = head->next;
}
printf("\n");
}
int main(void) {
//Node* head = node_create();
Node* head = NULL; //不要头结点
add_before_head(&head, 1);
add_before_head(&head, 2);
add_before_head(&head, 3);
add_before_head(&head, 4);
print_list(head);
int mid = middleElement(head);
printf("mid = %d\n",mid);
node_destroy(head);
return 0;
}
2.141.环形链表
链接:https://leetcode.cn/problems/linked-list-cycle/
思路:快慢指针
c
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
struct ListNode* fast = head;
struct ListNode* slow = head;
while (fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
if (fast == slow) { //快慢指针相遇,说明有环
return true;
}
}
return false;
}
完整代码
c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node {
int data;
struct node* next;
} Node;
//头插法
void add_before_head(Node** head, int value) {
Node* new_node = malloc(sizeof(Node));
new_node->data = value;
new_node->next = *head;
*head = new_node;
}
//1.求链表中间结点:快慢指针
int middleElement_2(Node* list) {
Node* fast = list;
Node* slow = list;
while (fast && fast->next) {
fast = fast->next->next;
slow = slow->next;
}
return slow->data;
}
void print_list(Node* head) {
while (head != NULL) {
printf("%d ", head->data);
head = head->next;
}
printf("\n");
}
int main(void) {
//直接在栈上创建链表
Node node8 = { 8, NULL };
Node node6 = { 6, &node8 };
Node node4 = { 4, &node6 };
Node node2 = { 2, &node4 };
print_list(&node2);
int mid = middleElement_2(&node2);
printf("mid = %d\n", mid);
return 0;
}
3.206.反转链表、LCR 024.反转链表
链接:https://leetcode.cn/problems/reverse-linked-list/
链接:https://leetcode.cn/problems/UHnkqh/description/
思路1:迭代
头插法,三指针 (previous、current、next)
c
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* current = head;
struct ListNode* previous = NULL;
while (current != NULL) {
struct ListNode* next = current->next; //next声明为current后一个
current->next = previous; //头插法反转
previous = current; //prev后移
current = next; //curr后移
}
return previous; //新的头节点
}
思路2:递归
时间复杂度:O(n)
空间复杂度:O(n),递归调用栈深度为n
c
struct ListNode* reverseList(struct ListNode* head) {
//1.递归出口(边界条件)
if(head == NULL || head->next == NULL){
return head;
}
//2.递归公式
struct ListNode* rest = reverseList(head->next); //问题规模由n减为n-1
//反转第一个结点,假设后n-1个结点已经反转
head->next->next = head;
head->next = NULL;
return rest;
}
4.21.合并两个有序链表
链接:https://leetcode.cn/problems/merge-two-sorted-lists/
思路:栈上创建哑结点,尾插法
c
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
struct ListNode dummyNode = {0, NULL}; ////在栈上创建哑结点,并初始化
struct ListNode* tail = &dummyNode;
//判空:处理空链表的情况
if (list1 == NULL) return list2;
if (list2 == NULL) return list1;
while(list1 != NULL && list2 != NULL){
if (list1->val < list2->val) {
tail->next = list1;
tail = list1;
list1 = list1->next;
}else{
tail->next = list2;
tail = list2;
list2 = list2->next;
}
} //list1和list2有一个为空
tail->next = (list1 != NULL) ? list1 : list2; //直接链接
return dummyNode.next;
}
5.61.旋转链表 【待做,Linux01】

链接:https://leetcode.cn/problems/rotate-list/description/
三、递归
1.509.斐波那契数列
链接:https://leetcode.cn/problems/fibonacci-number/
思路1:暴力递归
c
int fib(int n){
if(n==0 || n==1){
return n;
}
return fib(n-1) + fib(n-2);
}
思路2:动态规划
动态规划(Dynamic Programming,DP)是一种算法设计方法,用于解决那些可以被分解成重叠子问题的复杂问题。这种方法通过将问题拆分成更小、更简单的子问题来解决,每个子问题只解决一次,并将其结果存储起来,以便在解决其他子问题时可以直接使用这些结果,从而避免了重复计算。
动态规划通常用于优化问题,比如求最大值或最小值,例如寻找最短路径、最长公共子序列、背包问题等。这种方法特别适用于那些子问题重叠和最优子结构性质的问题,它可以显著减少计算量,提高效率。
c
int fib(int n){
if(n==0 || n==1) return n;
int sum = 0, n1 = 0, n2= 1; //0,1,1,2,3,5,8,13,21,34,55,89
for(int i = 2; i <= n; i++){
sum = n1 + n2;
n1 = n2;
n2 = sum;
}
return sum;
}
四、排序
1.912.排序数组
链接:https://leetcode.cn/problems/sort-an-array/description/
五、二叉树
1.104.二叉树的最大深度
链接:https://leetcode.cn/problems/maximum-depth-of-binary-tree/
思路1:递归先根遍历 + 参数传递 + 全局变量 (自顶向下传递信息)
c
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
int deep = 0;
void PreOrder(struct TreeNode* root, int h){
if(root == NULL) return;
if(h > deep) deep = h;
PreOrder(root->left, h + 1);
PreOrder(root->right, h + 1);
}
//递归后序遍历 + 函数返回值 (自底向上传递信息)
int maxDepth(struct TreeNode* root) {
deep = 0;
PreOrder(root,1); //初始深度为1
return deep;
}
思路2:递归后序遍历 + 函数返回值 (自底向上传递信息)
c
int maxDepth(struct TreeNode* root) {
if(root == NULL) return 0;
int l = maxDepth(root->left);
int r = maxDepth(root->right);
return l>r ? l+1 : r+1;
}
2.98.验证二叉搜索树
链接:https://leetcode.cn/problems/validate-binary-search-tree/description/
c
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
#include <limits.h>
long long cur_min = LLONG_MIN; //未遍历过结点的最小值
bool isBST = true;
void inOrder(struct TreeNode* root){
//边界条件
if(root == NULL) return;
//递归公式
inOrder(root->left);
if(root->val <= cur_min){
isBST = false;
return; //已经false了,可以直接返回
}else{
cur_min = root->val;
}
inOrder(root->right);
}
bool isValidBST(struct TreeNode* root) {
cur_min = LLONG_MIN;
isBST = true;
inOrder(root);
return isBST;
}
六、查找
1.寻找旋转排序数组中的最小值 (待做,Linux02)
链接:https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/description/
链接:https://leetcode.cn/problems/search-in-rotated-sorted-array/description/
链接:https://leetcode.cn/problems/search-in-rotated-sorted-array-ii/description/
思路:二分查找
2.275.H指数 (二分查找)
链接:https://leetcode.cn/problems/h-index-ii/description/
思路:
①H指数:至少有 h 篇论文分别被引用了至少 h 次
②第i篇论文被引用了citations[i]次,第mid篇论文被引用了citations[mid]次
③后一半的论文数量一共是n-mid篇,这n-mid篇的引用次数均 ≥ citations[mid]次
④答案一定是数组中的某个值,所以需要二分查找向左或向右移动区间
1.LeetCode官方题解:
c
//数组,有序:想到二分查找
int hIndex(int* citations, int n) {
int left = 0, right = n - 1; //闭区间
while(left <= right){
int mid = left + (right - left >> 1);
if( citations[mid] >= n-mid ){ //至少n-mid篇被引用了c[mid]次
right = mid - 1; //H指数应该更小,向左走
}else{
left = mid + 1; //H指数应该更小,向右走
}
}
return n - left;
}
2.花生题解1:
c
//数组,有序:想到二分查找
int hIndex(int* citations, int n) {
int left = 0, right = n - 1; //闭区间
while(left <= right){
int mid = left + (right - left >> 1);
if( citations[mid] > n-mid ){ //至少n-mid篇被引用了c[mid]次
right = mid - 1; //H指数应该更小,向左走
}else if(citations[mid] < n-mid){
left = mid + 1; //H指数应该更小,向右走
}else{ //相等,恰是H指数
return n-mid;
}
} // left > right
//如果 left 在 [0, n-1]范围内,那么 citations[left] 就是第一个大于 n - left的元素
//三种退出情况,都是 n-left
return n - left;
}
3.花生题解2:
c
七、STL容器
1.LRU缓存
链接:https://leetcode-cn.com/problems/lru-cache/