【Leetcode Sheet】Weekly Practice 2

Leetcode Test

1281 整数的各位积和之差(8.9)

给你一个整数 n,请你帮忙计算并返回该整数「各位数字之积」与「各位数字之和」的差。

提示:

  • 1 <= n <= 10^5

【原始代码】:

int subtractProductAndSum(int n){
    //1 <= n <= 10^5
    //except 100000, there're 5 bits
    if(n==100000){
        return -1;
    }
    int bits[5]={0,0,0,0,0,0};
    int cnt=0;
    while(n>0){
        bits[cnt++]=n%10;
        n/=10;
    }
    int multi=1,sum=0;
    for(int i=0;i<cnt;i++){
        multi*=bits[i];
        sum+=bits[i];
    }
    return (multi-sum);
}

【优化代码】

int subtractProductAndSum(int n) {
    int m = 1, s = 0;	//m是乘积,sum是求和
    while (n) {	//当n!=0时
        int x = n % 10;		//x是n的余数
        n /= 10;	//n缩小
        m *= x;		//m进行乘积
        s += x;		//s进行求和
    }
    return m - s;	//返回 乘积-求和
}
//减少位数的存储,空间复杂度为O(1)
//时间复杂度仍然为O(m),m为n的位数

【其他思路】

将n转为字符串,例如n是1234,则char temp=‘1234’

后续直接遍历strlen(temp),计算temp[i]-'0’的值即可

1289 下降路径最小和 II(8.10)

给你一个 n x n 整数矩阵 grid ,请你返回 非零偏移下降路径 数字和的最小值。

非零偏移下降路径 定义为:从 grid 数组中的每一行选择一个数字,且按顺序选出来的数字中,相邻数字不在原数组的同一列。

提示:

  • n == grid.length == grid[i].length
  • 1 <= n <= 200
  • -99 <= grid[i][j] <= 99
int minFallingPathSum(int** grid, int gridSize, int* gridColSize) {
    int first_min_sum = 0;
    int second_min_sum = 0;
    int first_min_index = -1;
    
    for (int i = 0; i < gridSize; i++) {    //遍历外层
        int cur_first_min_sum = INT_MAX;    //记录最小值
        int cur_second_min_sum = INT_MAX;   //记录次小值
        int cur_first_min_index = -1;   //记录最小值列编号
        for (int j = 0; j < gridSize; j++) {    //遍历内层
            int cur_sum = (j != first_min_index ? first_min_sum : second_min_sum) + grid[i][j];
            //当前求和计算,如果j和最小值列编号不一样,则添加最小值,否则添加次小值
            if (cur_sum < cur_first_min_sum) {  //如果当前求和,小于最小
                cur_second_min_sum = cur_first_min_sum;     //更新次小为之前的最小
                cur_first_min_sum = cur_sum;    //更新最小为当前的求和
                cur_first_min_index = j;    //更新比列编号
            } else if (cur_sum < cur_second_min_sum) {  //如果当前求和,小于次小
                cur_second_min_sum = cur_sum;   //更新次小为当前的求和
            }
        }
        first_min_sum = cur_first_min_sum;  //更新最小
        second_min_sum = cur_second_min_sum;    //更新次小
        first_min_index = cur_first_min_index;  ///更新列编号
    }
    return first_min_sum;
}

1572 矩阵对角线元素的和(8.11)

给你一个正方形矩阵 mat,请你返回矩阵对角线元素的和。

请你返回在矩阵主对角线上的元素和副对角线上且不在主对角线上元素的和。

提示:

  • n == mat.length == mat[i].length
  • 1 <= n <= 100
  • 1 <= mat[i][j] <= 100
int diagonalSum(int** mat, int matSize, int* matColSize){
    //n x n matrix
    int n=matSize,sum=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if((i==j)||(i+j==n-1)){    
                //i==j 主对角线;i+j==n-1 次对角线
                sum+=mat[i][j];
            }
        }
    }
    return sum;
}

2681 英雄的力量(8.1补)

给你一个下标从 0 开始的整数数组 nums ,它表示英雄的能力值。如果我们选出一部分英雄,这组英雄的 力量 定义为:

  • i0i1 ,… ik 表示这组英雄在数组中的下标。那么这组英雄的力量为 max(nums[i0],nums[i1] ... nums[ik])2 * min(nums[i0],nums[i1] ... nums[ik])

请你返回所有可能的 非空 英雄组的 力量 之和。由于答案可能非常大,请你将结果对 109 + 7 取余。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 109
int cmp(void *a,void *b){
    return *(int*)a-*(int*)b;
}

int sumOfPower(int* nums, int numsSize){
    qsort(nums,numsSize,sizeof(int),cmp);   
    //元素的顺序不影响答案,先排序
    //power = max*max*min
    int dp = 0, preSum = 0;
    int res = 0, mod = 1e9 + 7;
    for (int i = 0; i < numsSize; i++) {
        dp = (nums[i] + preSum) % mod;
        preSum = (preSum + dp) % mod;
        res = (int) ((res + (long long) nums[i] * nums[i] % mod * dp) % mod);
        if (res < 0) {
            res += mod;
        }
    }
    return res;
}

23 合并K个升序链表(8.12)

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

提示:

  • k == lists.length
  • 0 <= k <= 10^4
  • 0 <= lists[i].length <= 500
  • -10^4 <= lists[i][j] <= 10^4
  • lists[i]升序 排列
  • lists[i].length 的总和不超过 10^4
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

int cmp(const void * a, const void * b)//升序子函数
{
    return *(int *)a - *(int *)b;
}
struct ListNode* mergeKLists(struct ListNode** lists, int listsSize){
    if(listsSize == 0 )
    {
        return NULL;
    }
    int ans[10000];//临时保存链表值
    int node = 0;
    for(int i = 0; i <listsSize; i++)//保存所有链表值
    {
        while(lists[i])
        {
            ans[node++] = lists[i]->val;
            lists[i] = lists[i]->next;
        }
    }
    qsort(ans, node, sizeof(int), cmp);//排序
    struct ListNode * h = NULL;
    struct ListNode * root = NULL;
    for(int i = 0; i < node; i++)//转换为链表存储
    {
        struct ListNode * r = malloc(sizeof(struct ListNode));
        r->val = ans[i];
        r->next = NULL;
        if(root == NULL)
        {
            h = r;
            root = r;
        }
        else
        {
            h->next = r;
            h = r;
        }  
    }
    return root;
}

88 合并两个有序数组(8.13)

给你两个按 非递减顺序 排列的整数数组 nums1nums2,另有两个整数 mn ,分别表示 nums1nums2 中的元素数目。

请你 合并 nums2nums1 中,使合并后的数组同样按 非递减顺序 排列。

**注意:**最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n

提示:

  • nums1.length == m + n
  • nums2.length == n
  • 0 <= m, n <= 200
  • 1 <= m + n <= 200
  • -109 <= nums1[i], nums2[j] <= 109
int cmp(void *a,void *b){
    return *(int*)a-*(int*)b;
}

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    int cnt=0,i=m;
    while(cnt<n){
        nums1[i++]=nums2[cnt++];
    }
    qsort(nums1,(n+m),sizeof(int),cmp);
}

a former method

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
    for(int i=0;i!=n;i++){
        nums1[m+i]=nums2[i];
    }
    int minno;
    for(int i=0;i<m+n-1;i++){
        minno=i;
        for(int j=i+1;j<m+n;j++){
            if(nums1[j]<nums1[minno]){
                minno=j;
            }
        }
        //找到i后面的最小数,交换i位置和minno位置
        int temp=nums1[i];
        nums1[i]=nums1[minno];
        nums1[minno]=temp;
    }
}

a new-spaced method: O(n+m) of both time and space

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
    int p1 = 0, p2 = 0;
    int sorted[m + n];	//new-spaced
    int cur;
    while (p1 < m || p2 < n) {
        if (p1 == m) {
            cur = nums2[p2++];
        } else if (p2 == n) {
            cur = nums1[p1++];
        } else if (nums1[p1] < nums2[p2]) {
            cur = nums1[p1++];
        } else {
            cur = nums2[p2++];
        }
        sorted[p1 + p2 - 1] = cur;
    }
    for (int i = 0; i != m + n; ++i) {
        nums1[i] = sorted[i];
    }
}

617 合并二叉树(8.14)

给你两棵二叉树: root1root2

想象一下,当你将其中一棵覆盖到另一棵之上时,两棵树上的一些节点将会重叠(而另一些不会)。你需要将这两棵树合并成一棵新二叉树。合并的规则是:如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点。

返回合并后的二叉树。

注意: 合并过程必须从两个树的根节点开始。

提示:

  • 两棵树中的节点数目在范围 [0, 2000]
  • -104 <= Node.val <= 104
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

//深度优先搜索 dfs
struct TreeNode* mergeTrees(struct TreeNode* root1, struct TreeNode* root2){
    //如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;
    //否则,不为 null 的节点将直接作为新二叉树的节点。
    if(root1 == NULL) return root2;
    else if(root2 == NULL) return root1;
    struct TreeNode* result=malloc(sizeof(struct TreeNode));
    result->val=root1->val + root2->val;
    result->left=mergeTrees(root1->left,root2->left); 	//左子树递归
    result->right=mergeTrees(root1->right,root2->right);	//右子树递归
    return result;
}

C++:

递归,直接在原root1进行修改

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if (root1 && root2) {
            root1->val += root2->val;
            root1->left = mergeTrees(root1->left, root2->left);
            root1->right = mergeTrees(root1->right, root2->right);
        }
        return root1 ? root1 : root2;
    }
};

另可进行广度优先(较为复杂)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MorleyOlsen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值