11

《一、链表》

1. 两数之和

/**

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

*/

int* twoSum(int* nums, int numsSize, int target, int* returnSize) {

int a=0, b=0, i, j;

int *arr = malloc(sizeof(int) * 2);

for(i=0; i<numsSize-1; i++){

for(j=i+1; j<numsSize; j++){

if(nums[i] + nums[j] == target){

arr[0] = i;

arr[1] = j;

break;

}

}

}

*returnSize = 2;

return arr;

}

160. 相交链表

//————灵神!!!只是说相交,又没有说后面完全重合。

/**

* //系统已经定义好的结构体

* Definition for singly-linked list.

* struct ListNode {

* int val;

* struct ListNode *next;

* };

*/

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {

struct ListNode* p = headA;

struct ListNode* q = headB;

//如果相交前的距离不同,两人走完自己的路还会走对方的前一段路

while(p != q){

p = p!=NULL ? p->next:headB;

q = q!=NULL ? q->next:headA;

}

return p;

}

206. 反转链表

/**

* Definition for singly-linked list.

* struct ListNode {

* int val;

* struct ListNode *next;

* };

*/

struct ListNode* reverseList(struct ListNode* head) {

struct ListNode *nxt;

struct ListNode *pre = NULL;

struct ListNode *cur = head;

while(cur){

nxt = cur->next;

cur->next = pre;

pre = cur;

cur = nxt;

}

return pre;

}

234. 回文链表

/**

* Definition for singly-linked list.

* struct ListNode {

* int val;

* struct ListNode *next;

* };

*/

bool isPalindrome(struct ListNode* head) {

/*第一步————新建一个链表存放反转链表*/

//将反转链表存储在一个新的链表中

struct ListNode* l;

//初始化新的链表

l = (struct ListNode*)malloc(sizeof(struct ListNode));

l->next = NULL;

//进行反转操作,p是用于构造新链表的,q是用于从旧链表取值和遍历的

struct ListNode *q = head, *p; // 这里要对每个变量前面都写*!!!

while(q!=NULL){

//初始化构造结点

p = (struct ListNode*)malloc(sizeof(struct ListNode));

p->val = q->val;

//头插法

p->next = l->next;

l->next = p;

//旧数组再后移

q = q->next;

}

/*第二步————开始逐一对比*/

struct ListNode* i = head;

struct ListNode* j = l->next;

while(i != NULL){

if(i->val != j->val){

return false;

}

i = i->next;

j = j->next;

}

return true;

}

141. 环形链表

/**

* Definition for singly-linked list.

* struct ListNode {

* int val;

* struct ListNode *next;

* };

*/

/*使用快慢指针,慢指针每次走一步,如果有环,一定会走到环里。

再看相对速度,每次快指针比慢指针多走一步,肯定会追上慢指针。*/

bool hasCycle(struct ListNode *head) {

struct ListNode* slow = head;

struct ListNode* fast = head;

//fast!=NULL保证了快指针没到表尾,fast->next!=NULL保证fast->next->next无空指针

while(fast!=NULL && fast->next!=NULL){

slow = slow->next;

fast = fast->next->next;

if(slow == fast){

return true;

}

}

return false;

}

21. 合并两个有序链表

/*————danny的常规方法,注意和回文链表进行区别,这个可以直接用两个现有的链表进行构造,因为原有链表不需要保留;

而前面的回文链表需要保留原来链表进行对比,所以不能像这题这样操作。*/

/**

* Definition for singly-linked list.

* struct ListNode {

* int val;

* struct ListNode *next;

* };

*/

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {

//(1)如果l1/l2有空的,则直接将另一个链表给返回

if(!l1){

return l2;

}

if(!l2){

return l1;

}

//(2)创建一个头结点并初始化

struct ListNode *head = (struct ListNode*)malloc(sizeof(struct ListNode));

head->next = NULL; // 防止脏数据

struct ListNode* s = head; // 使用s进行操作,而不是头结点head

//(3)对以head为头结点的链表进行构造(只是对地址操作,并不是创建大量结点)

while(l1 && l2){

if(l1->val < l2->val){

s->next = l1;

l1 = l1->next;

}

else{

s->next = l2;

l2 = l2->next;

}

s = s->next; // 因为x最开始指向的是头结点,每次将下一个位置安排好后,将t移到新链表的最后一个位置

}

//(4)如果都有数据的区间结束,l1还有元素,则t后面直接接剩余的值

if(l1){

s->next = l1;

}

else if(l2){

s->next = l2;

}

//(5)将构造好的链表的第一个具体结点返回

return head->next;

}

《二、树》

94. 二叉树的中序遍历

/** 将遍历的结果保存在数组中

* 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().

*/

void inOrder(struct TreeNode* root, int *arr, int *arrSize){ // 都传入指针是因为都需要修改

if(!root){

return ;

}

else{

inOrder(root->left, arr, arrSize);

arr[(*arrSize)++] = root->val; // 初始化arrSize为0,所以对应为下标,先赋值再进行++

inOrder(root->right, arr, arrSize);

}

}

int* inorderTraversal(struct TreeNode* root, int* returnSize) {

int *arr = (int*)malloc(sizeof(int)*101); // 如果直接写int arr[101],就是局部变量定义在栈上;malloc是在堆上

*returnSize = 0; // 要初始化!!!

inOrder(root, arr, returnSize);

return arr;

}

104. 二叉树的最大深度

/**

* Definition for a binary tree node.

* struct TreeNode {

* int val;

* struct TreeNode *left;

* struct TreeNode *right;

* };

*/

int maxDepth(struct TreeNode* root) {

if(!root){

return 0;

}

else{

int lefthigh = maxDepth(root->left);

int righthigh = maxDepth(root->right);

return lefthigh > righthigh ? (lefthigh+1) : (righthigh+1);

}

}

226. 翻转二叉树

/**

* Definition for a binary tree node.

* struct TreeNode {

* int val;

* struct TreeNode *left;

* struct TreeNode *right;

* };

*/

struct TreeNode* invertTree(struct TreeNode* root) {

if(! root){

return NULL;

}

struct TreeNode* p = invertTree(root->left); // 得到翻转过的左子树

struct TreeNode* q = invertTree(root->right); // 得到翻转过的右子树

root->left = q; // 令当前根结点的左子树等于翻转过的右子树

root->right = p;

return root;

}

101. 对称二叉树

/**

* Definition for a binary tree node.

* struct TreeNode {

* int val;

* struct TreeNode *left;

* struct TreeNode *right;

* };

*/

bool isSame(struct TreeNode *p, struct TreeNode *q){

if(p==NULL || q==NULL){

return p==q;

}

return (p->val==q->val && isSame(p->left, q->right) && isSame(p->right, q->left)); // 只是修改100题的返回值

}

bool isSymmetric(struct TreeNode* root) {

return isSame(root->left, root->right);

}

543. 二叉树的直径

/** 深度优先搜索

* Definition for a binary tree node.

* struct TreeNode {

* int val;

* struct TreeNode *left;

* struct TreeNode *right;

* };

*/

// 计算当前结点下面树的高度,并在计算过程中不断更新直径max

int maxNum(struct TreeNode* r, int *max){

if(r == NULL){

return 0;

}

int left = maxNum(r->left, max); // 通过left接收该节点左子树的高度

int right = maxNum(r->right, max); // 通过right接收该节点右子树的高度

*max = *max > (left+right) ? *max : (left+right); // max与当前结点左右子树深度之和进行比较,更新

return (left > right ? left+1 : right+1); // 本质上,这个函数就是为了计算树的深度

}

int diameterOfBinaryTree(struct TreeNode* root) {

int max = 0;

maxNum(root, &max);

return max;

}

108. 将有序数组转换为二叉搜索树

/**

发现子问题和原问题相似,就是递归:

1.先找到数组中间位置i,根为arr[i],然后左右继续这样操作;

2.递归边界:如果数组长度等于0,返回空节点。

3.注意如果数组长度为偶数,答案就不是唯一的,这里我们约定偶数长度数组根节点为靠右侧的那个结点,下标就是n/2。

* Definition for a binary tree node.

* struct TreeNode {

* int val;

* struct TreeNode *left;

* struct TreeNode *right;

* };

*/

struct TreeNode* bulid(int *nums, int left, int right){ // left是起始下标(包含);right是结束下标的下一个位置(不包含)

if(left == right){ // 数组起始位置等于数组长度了0==0

return NULL;

}

else{

int m = left+(right-left)/2; // 如果直接“(left+right)/2”可能导致内存溢出

struct TreeNode* n = (struct TreeNode*)malloc(sizeof(struct TreeNode));

n->val = nums[m];

n->left = bulid(nums, left, m);

n->right = bulid(nums, m+1, right);

return n;

}

}

struct TreeNode* sortedArrayToBST(int* nums, int numsSize) {

return bulid(nums, 0, numsSize);

}

20. 有效的括号

// 本题将s看做栈使用,自定义int top,通过top指针模拟栈的操作

bool isValid(char* s) {

// 这样定义后,mp中所有元素初始化为0 :

char mp[128] = {};

// 这样赋值后,mp中只有右括号的ASCII码值作为下标对应的数组值,其他所有(包括左括号)的ASCII对应的数组值皆为0:

mp[')'] = '(';

mp[']'] = '[';

mp['}'] = '{';

int top = 0; // 定义栈顶指针,但初始化为0,这里不是-1

for(int i=0; s[i]; i++){ // 遍历字符数组s

char c = s[i];

if(mp[c] == 0){ // 左括号

s[top++] = c; // 入栈

}

/*说明:只要不满足if就会进入else if,先判空,如果不空再取栈顶元素(左括号)与右括号进行匹配*/

//这里面--top操作已经完成元素出栈了,如果匹配就出栈后再循环,如果不匹配,直接返回false

else if(top==0 || s[--top] != mp[c]){ // 右括号与上一个入栈的左括号进行匹配

return false;

}

}

return (top == 0); // 全部匹配结束

}

121. 买卖股票的最佳时机

#define MAX(a, b) a>b?a:b // 定义宏,返回两个数中的最大值

#define MIN(a, b) a<b?a:b // 定义宏,返回两个数中的最小值

int maxProfit(int* prices, int pricesSize) {

int ans = 0; // 初始化最大利润为 0

int min_price = prices[0]; // 初始化最低价格为数组的第一个元素

// 同时更新当前最大利润和当前最小买入价格

for (int i = 1; i < pricesSize; i++) {

int p = prices[i]; // 当前价格

ans = MAX(ans, p - min_price); // 更新最大利润为MAX(当前最大利润, 当前价格-当前最低价格)

min_price = MIN(min_price, p); // 更新最低价格为MIN(当前最小价格, 当前价格)

}

return ans; // 返回最大利润

}

70. 爬楼梯

/*递归方程:f[n] = f[n-1] + f[n-2]

因为每次只能走1/2个台阶。 */

int climbStairs(int n) {

// 这块的作用看line10注释

if(n==1){

return 1;

}

int dp[n+1]; // 其中dp[0]的位置是空着的,dp[i]直接表示上i级台阶有多少种方法

dp[1] = 1;

dp[2] = 2; // 这个2是下标2,如果前面没有n=1的判断,n=1时,创造dp[2],只能访问到dp[1],这里将会越界

for(int i=3; i<=n; i++){ // 最大的下标为n

dp[i] = dp[i-1] + dp[i-2]; // 从开始条件一步步算到目的情况

}

return dp[n];

}

136. 只出现一次的数字

// 线性时间复杂度————O(n),不能使用双重循环O(n²)

/*使用位运算“异或”解题:对“ ^ ”,有3^3=0、3^0=3。所以只需定义一个变量,在循环中与数组所有值异或即可,相同的会自动变为0*/

int singleNumber(int* nums, int numsSize) {

int num = 0;

for(int i=0; i<numsSize; i++){

num ^= nums[i]; // num = num^nums[i]

}

return num;

}

169. 多数元素

/*将数组 nums 中的所有元素按照单调递增或单调递减的顺序排序,那么下标为 ⌊2/n​⌋ 的元素(下标从 0 开始)一定是众数。*/

// 说明:因为出现次数大于一半了,就算从头排,中间位置也是他

int majorityElement(int* nums, int numsSize) {

int temp;

//冒泡排序

for(int i=0; i<numsSize; i++){

int change = 0;

for(int j=0; j<numsSize-i-1; j++){

if(nums[j]>nums[j+1]){

temp = nums[j];

nums[j] = nums[j+1];

nums[j+1] = temp;

change = 1;

}

}

if(!change){

break;

}

}

return nums[numsSize/2];

}

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务