力扣一周学习(5.4~5.10)

力扣一周学习(5.4~5.10)

第一次尝试力扣刷题,发现许多未知的领域,发现自己还是有许多要学的,我才大一,,果然学长说的是对的哈哈哈哈哈,还有太多太多没学了。

一、两数之和

在这里插入图片描述
严格意义上,这并不是第一次接触的题哈哈哈,开头就简单多好呀。

int* twoSum(int* nums, int numsSize, int target, int* returnSize){
    int *result = (int *)malloc(sizeof(int) *2);
    \\定义输出结果的数组。
    for(int i = 0; i < numsSize - 1; i++)
        for(int j = i + 1; j < numsSize ; j ++)
            if(nums[i] + nums[j] == target)
                {
                    result[0] = i;
                    result[1] = j;
                    *returnSize = 2;
                    return  result;
                }
    return result;
}

在这里插入图片描述
就很离谱哈哈哈,暴力破解的确是这个样子的。执行时间的确是挺长的。

本题的优解是用哈希表,不过因为笔者未学到,便暂不继续,(不会那你不会去学啊),就不就不哈哈哈。快学到了快学到了。



二、 整数反转

在这里插入图片描述
对于回文之类题目,可以用数学法,不一定用字符转换,

本题是一道看似简单的整数反转,其中的坑就是,定义的类型是否会溢出,警惕要有编程要有良好的安全性。

int reverse(int x){
    int n = 0, sum = 0;
    while(x != 0)
    {
        n = x % 10;
        if(sum > INT_MAX/10 || (sum == INT_MAX/10 && n > 7))
            return 0; 
        if(sum < INT_MIN/10 || (sum == INT_MIN/10 && n < -8))
            return 0;
        sum = sum * 10 + n;
        x = x / 10;
    }
    return sum;
}

下面给出部分C语言数据结构的字节

类型32位64位
char11
short22
int44
long48
long long88
float44
double88

在这里插入图片描述
什么时候才能双百呢(摊手)



三、回文数

在这里插入图片描述
ko nuo 回文数 哒(┑( ̄Д  ̄)┍)
简单来看,转成字符串是最省事的,但是进阶的说不用字符串,那就不用咯。
整数转换,切记溢出问题,这道题巧妙的地方在于,你不用全部转换,因为是回文数,只要转换一半通过对比就可以。

bool isPalindrome(int x){
    if(x < 0 || (x % 10 == 0 && x != 0))	//结尾为0的不是回文数
		return false;
	int y = 0;
	while(x > y)
	{
		y = x % 10 + y * 10;
		x = x / 10;
	}
	return x == y || x == y /10;		//奇数情况除以10
}

有一说一,我觉得挺厉害的哈哈哈哈这个代码,(不是你写的吗),当然是一半写一半借鉴的啦~
在这里插入图片描述



四、合并两个有序链表

在这里插入图片描述
一开始做这道的时候,一拍案,我会,简单,然后错了N多次,(摊手)。
这道题我的解法是创建一个头结点,通过比较整数大小,指向小的结点。

struct ListNode {
    int val;
    struct ListNode *next;
    };
    
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    struct ListNode *p, *head;
    p = (struct ListNode *)malloc(sizeof(struct ListNode));
    head = p;
    
    while(l1 != NULL && l2 != NULL)
    {
        if(l1->val > l2->val)
        {
            p->next = l2;
            l2 = l2->next;
        }
        else
        {
            p->next = l1;
            l1 = l1->next;
        }
        p = p->next;
    }
    
    p->next = l1 == NULL? l2: l1;
    return head->next;
}

其实这种题我偏向于重新创建结点,即不改变原本两条链表的顺序。
在这里插入图片描述
这里要提一下,三目运算符是真的看起来舒服(= v =)



五、两数相加

在这里插入图片描述

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

struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2){
    struct ListNode *p1 = l1, *p2 = l2, *head = NULL, *p = NULL, *q = NULL;
    head = (struct ListNode *)malloc(sizeof(struct ListNode));					// 头结点的建立
    head->next = NULL;
    p = head;
    
    // sum是相加之和,carry是sum的十位数
    int a1 = 0, a2 = 0, carry = 0, sum = 0;
    
    while(p1 != NULL || p2 != NULL)					// 长短不一的链表也可适用
    { 
        a1 = p1 != NULL? p1->val: 0;
        a2 = p2 != NULL? p2->val: 0;
        sum = (a1 + a2 + carry) % 10;				// 求余是为了只得到个位数
        carry = (a1 + a2 + carry) / 10;				// 求sum的十位数是0还是1

        q = (struct ListNode *)malloc(sizeof(struct ListNode));					// 建立新结点
        q->val = sum;
        q->next = NULL;
        p->next = q;
        p = p->next;

        p1 = p1 != NULL? p1->next: p1;
        p2 = p2 != NULL? p2->next: p2;
    }
    
    if(carry != 0)				// 如果carry等于1,说明需要多一位1
    {
        q = (struct ListNode *)malloc(sizeof(struct ListNode));
        q->val = carry;
        q->next = NULL;
        p->next = q;
    }
    return head->next;
}

这道题是先建立头结点,然后建立结点存储相加的数。解法中巧妙的是运用carry作为相加之后的十位数,并持续到下一个结点。
在这里插入图片描述



六、另一个树的子树

在这里插入图片描述在这里插入图片描述
本题可以采用暴力解法,即对每个结点进行遍历,得出结果。(暴力天下第一

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

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

bool isSubtree(struct TreeNode* s, struct TreeNode* t){
    if(t == NULL)   return true;
    if(s == NULL)   return false;
    return  isSametree(s, t) || isSubtree(s->left, t) || isSubtree(s->right, t);
}

有一说一,递归是真的简洁也是真的离谱哈哈哈哈,想不出这么简洁,还是要多多练习啊。
在这里插入图片描述
其实这是多运行几遍后的0x0,第一次时间36ms,击败了10%多的用户orz。

本题还有另一种解法,字符串解法,很容易出现一个问题,如果子树少了一个结点呢,那么普通的转换成字符串就会报错,所以要引入一种改进的
图源来自力扣官方,侵删

图源来自力扣,侵删

c++代码如下

class Solution {
public:
    vector <int> sOrder, tOrder;
    int maxElement, lNull, rNull;

    void getMaxElement(TreeNode *o) {
        if (!o) return;
        maxElement = max(maxElement, o->val);
        getMaxElement(o->left);
        getMaxElement(o->right);
    }

    void getDfsOrder(TreeNode *o, vector <int> &tar) {
        if (!o) return;
        tar.push_back(o->val);
        if (o->left) getDfsOrder(o->left, tar);
        else tar.push_back(lNull);
        if (o->right) getDfsOrder(o->right, tar);
        else tar.push_back(rNull);
    }

    bool kmp() {
        int sLen = sOrder.size(), tLen = tOrder.size();
        vector <int> fail(tOrder.size(), -1);
        for (int i = 1, j = -1; i < tLen; ++i) {
            while (j != -1 && tOrder[i] != tOrder[j + 1]) j = fail[j];
            if (tOrder[i] == tOrder[j + 1]) ++j;
            fail[i] = j;
        }
        for (int i = 0, j = -1; i < sLen; ++i) {
            while (j != -1 && sOrder[i] != tOrder[j + 1]) j = fail[j];
            if (sOrder[i] == tOrder[j + 1]) ++j;
            if (j == tLen - 1) return true;
        }
        return false;
    }

    bool isSubtree(TreeNode* s, TreeNode* t) {
        maxElement = INT_MIN;
        getMaxElement(s);
        getMaxElement(t);
        lNull = maxElement + 1;
        rNull = maxElement + 2;

        getDfsOrder(s, sOrder);
        getDfsOrder(t, tOrder);

        return kmp();
    }
};

因为笔者没学过C++,所以不是很懂它的数组是否可以设置静态不定长,所以我就给不出C的,菜是原罪。希望能出一个专门说这道题的嘻嘻。

那就一次六题吧2333,慢慢积累,加油吧~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值