【Leecode 随笔】C语言版看了不后悔系列持续更新中。。。

文章目录

🌈你好呀!我是 山顶风景独好

🎈欢迎踏入我的博客世界,能与您在此邂逅,真是缘分使然!😊

🌸愿您在此停留的每一刻,都沐浴在轻松愉悦的氛围中。

📖这里不仅有丰富的知识和趣味横生的内容等您来探索,更是一个自由交流的平台,期待您留下独特的思考与见解。🌟

🚀让我们一起踏上这段探索与成长的旅程,携手挖掘更多可能,共同进步!💪✨

题目一:两数相除

题目描述

给定两个整数 dividend 和 divisor,要求在不使用乘法、除法和模运算的情况下,实现两数相除。返回商(整数部分)。

示例1:

输入: dividend = 10, divisor = 3

输出: 3

示例2:

输入: dividend = 7, divisor = -3

输出: -2

注意:

被除数和除数均为 32 位有符号整数。

除数不能为零。

假设环境只能存储 32 位有符号整数,其数值范围是 [−2^31, 2^31 − 1]。为此,如果结果超过此范围,请返回 2^31 − 1(即 Integer.MAX_VALUE)或 −2^31(即 Integer.MIN_VALUE)。

解题思路

这道题的核心在于模拟除法运算。由于不能使用乘法、除法和模运算,我们可以使用位运算来实现。具体思路如下:

  • 处理被除数为0的特殊情况,直接返回0。
  • 处理被除数为最小值且除数为-1的特殊情况,因为此时结果会溢出,返回最大值。
  • 记录结果的符号,并将被除数和除数都转为负数进行计算,以避免溢出。
  • 使用左移运算(<<)来找到最接近被除数的除数倍数,并累加结果。

示例代码

c 复制代码
#include <limits.h>  
  
int divide(int dividend, int divisor) {  
    // 处理被除数为0的情况  
    if (dividend == 0) {  
        return 0;  
    }  
      
    // 处理被除数为最小值且除数为-1的情况  
    if (dividend == INT_MIN && divisor == -1) {  
        return INT_MAX;  
    }  
      
    // 记录结果的符号  
    int sign = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1;  
      
    // 将被除数和除数都转为负数  
    long long absDividend = labs((long long)dividend);  
    long long absDivisor = labs((long long)divisor);  
      
    int result = 0;  
    while (absDividend >= absDivisor) {  
        long long temp = absDivisor;  
        long long multiple = 1;  
          
        // 使用左移运算找到最接近被除数的除数倍数  
        while (absDividend >= (temp << 1)) {  
            temp <<= 1;  
            multiple <<= 1;  
        }  
          
        // 减去找到的倍数,并累加结果  
        absDividend -= temp;  
        result += multiple;  
    }  
      
    return sign * result;  
}  
  
// 示例测试  
int main() {  
    int dividend1 = 10, divisor1 = 3;  
    int dividend2 = 7, divisor2 = -3;  
    printf("Dividend: %d, Divisor: %d, Result: %d\n", dividend1, divisor1, divide(dividend1, divisor1));  
    printf("Dividend: %d, Divisor: %d, Result: %d\n", dividend2, divisor2, divide(dividend2, divisor2));  
    return 0;  
}

深入剖析

  • 符号处理:通过 (dividend < 0) ^ (divisor < 0) 来判断结果的符号,异或运算使得当且仅当两者符号不同时结果为负。
  • 转为负数:为了避免在后面的计算中溢出,我们将被除数和除数都转为负数(使用 labs 取绝对值后再加负号)。因为在C语言中,负数的范围比正数多一个值(即 INT_MIN),这样可以防止在取反时出现溢出。
  • 位运算优化:通过左移运算来快速找到最接近被除数的除数倍数,提高了算法的效率。

题目二:加一

题目描述

给定一个由数字组成的非空数组,表示一个非负整数,在该数的基础上加一,并返回新的数组。

示例1:

输入: [1, 2, 3]

输出: [1, 2, 4]

示例2:

输入: [9, 9, 9]

输出: [1, 0, 0, 0]

解题思路

这道题主要考察对数组操作的理解。从数组的最后一位开始,逐位加一并检查是否需要进位。如果某一位加一后小于10,则可以直接返回结果;否则,需要继续向前一位进位。

示例代码

c 复制代码
#include <stdio.h>  
#include <stdlib.h>  
  
int* plusOne(int* digits, int digitsSize, int* returnSize) {  
    // 从后往前遍历数组  
    for (int i = digitsSize - 1; i >= 0; i--) {  
        // 当前位加一  
        if (digits[i] + 1 < 10) {  
            digits[i]++;  
            *returnSize = digitsSize;  
            return digits;  
        } else {  
            // 需要进位,当前位变为0  
            digits[i] = 0;  
        }  
    }  
      
    // 如果所有位都需要进位,则需要扩展数组大小  
    int* newDigits = (int*)malloc((digitsSize + 1) * sizeof(int));  
    newDigits[0] = 1; // 最高位为1  
    for (int i = 1; i <= digitsSize; i++) {  
        newDigits[i] = 0; // 其余位为0  
    }  
      
    *returnSize = digitsSize + 1;  
    return newDigits;  
}  
  
// 示例测试  
int main() {  
    int digits1[] = {1, 2, 3};  
    int digitsSize1 = 3;  
    int returnSize1;  
    int* result1 = plusOne(digits1, digitsSize1, &returnSize1);  
    printf("Result 1: ");  
    for (int i = 0; i < returnSize1; i++) {  
        printf("%d ", result1[i]);  
    }  
    printf("\n");  
      
    int digits2[] = {9, 9, 9};  
    int digitsSize2 = 3;  
    int returnSize2;  
    int* result2 = plusOne(digits2, digitsSize2, &returnSize2);  
    printf("Result 2: ");  
    for (int i = 0; i < returnSize2; i++) {  
        printf("%d ", result2[i]);  
    }  
    printf("\n");  
      
    // 释放动态分配的内存  
    free(result2);  
      
    return 0;  
}

深入剖析

  • 进位处理:从数组的末尾开始逐一处理,如果当前位加一后小于10,则直接返回结果;否则,将当前位设为0,并继续向前一位进位。
  • 数组扩展:如果所有位都需要进位(如示例2中的情况),则需要扩展数组的大小,并在新的数组的最高位设为1,其余位设为0。

题目三:快乐数

题目描述

编写一个算法来判断一个数是不是"快乐数"。一个"快乐数"定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程,最终如果得到1,则是快乐数;如果得到无限循环的其他数,则不是快乐数。

示例1:

输入: 19

输出: true

解释:

1^2 + 9^2 = 82

8^2 + 2^2 = 68

6^2 + 8^2 = 100

1^2 + 0^2 + 0^2 = 1

示例2:

输入: 4

输出: false

解释:

4^2 = 16

1^2 + 6^2 = 37

3^2 + 7^2 = 58

5^2 + 8^2 = 89

8^2 + 9^2 = 145

1^2 + 4^2 + 5^2 = 42

4^2 + 2^2 = 20

解题思路

这道题可以使用哈希集合(HashSet)来检测循环。具体思路如下:

定义一个辅助函数 getSquareSum,用来计算一个整数各位数字的平方和。

在主函数中,使用一个循环来不断计算当前数的平方和,并检查是否出现过之前的数(即是否进入了循环)。

使用一个哈希集合来存储已经出现过的数,如果在计算过程中发现当前数已经在集合中,则说明进入了循环,返回 false。

如果计算过程中得到了 1,则说明是快乐数,返回 true。

示例代码

c 复制代码
#include <stdio.h>  
#include <stdlib.h>  
#include <stdbool.h>  
  
// 定义哈希集合的节点结构  
typedef struct HashNode {  
    int key;  
    struct HashNode* next;  
} HashNode;  
  
// 创建哈希集合  
HashNode** createHashSet(int size) {  
    HashNode** hashSet = (HashNode**)malloc(size * sizeof(HashNode*));  
    for (int i = 0; i < size; i++) {  
        hashSet[i] = NULL;  
    }  
    return hashSet;  
}  
  
// 哈希函数  
int hashFunction(int key, int size) {  
    return abs(key) % size;  
}  
  
// 在哈希集合中添加元素  
void addToHashSet(HashNode** hashSet, int key, int size) {  
    int index = hashFunction(key, size);  
    HashNode* newNode = (HashNode*)malloc(sizeof(HashNode));  
    newNode->key = key;  
    newNode->next = hashSet[index];  
    hashSet[index] = newNode;  
}  
  
// 检查元素是否在哈希集合中  
bool isInHashSet(HashNode** hashSet, int key, int size) {  
    int index = hashFunction(key, size);  
    HashNode* currentNode = hashSet[index];  
    while (currentNode != NULL) {  
        if (currentNode->key == key) {  
            return true;  
        }  
        currentNode = currentNode->next;  
    }  
    return false;  
}  
  
// 释放哈希集合的内存  
void freeHashSet(HashNode** hashSet, int size) {  
    for (int i = 0; i < size; i++) {  
        HashNode* currentNode = hashSet[i];  
        while (currentNode != NULL) {  
            HashNode* temp = currentNode;  
            currentNode = currentNode->next;  
            free(temp);  
        }  
    }  
    free(hashSet);  
}  
  
// 计算一个数的各位数字的平方和  
int getSquareSum(int num) {  
    int sum = 0;  
    while (num > 0) {  
        int digit = num % 10;  
        sum += digit * digit;  
        num /= 10;  
    }  
    return sum;  
}  
  
// 判断一个数是否为快乐数  
bool isHappy(int n) {  
    int hashSetSize = 1000; // 设置哈希集合的大小  
    HashNode** hashSet = createHashSet(hashSetSize);  
  
    while (n != 1 && !isInHashSet(hashSet, n, hashSetSize)) {  
        addToHashSet(hashSet, n, hashSetSize);  
        n = getSquareSum(n);  
    }  
  
    bool result = (n == 1);  
    freeHashSet(hashSet, hashSetSize);  
    return result;  
}  
  
// 示例测试  
int main() {  
    int num1 = 19;  
    int num2 = 4;  
    printf("Number: %d, Is Happy: %s\n", num1, isHappy(num1) ? "true" : "false");  
    printf("Number: %d, Is Happy: %s\n", num2, isHappy(num2) ? "true" : "false");  
    return 0;  
}

深入剖析

  • 哈希集合:使用哈希集合来存储已经出现过的数,以便快速检测循环。这里实现了一个简单的哈希集合,包括创建、添加、检查和释放内存的功能。
  • 平方和计算:通过 getSquareSum 函数来计算一个数的各位数字的平方和,这是解题过程中的关键步骤。
  • 循环检测:在主函数 isHappy 中,使用一个循环来不断计算平方和,并检查是否进入了循环。如果得到了 1,则说明是快乐数;如果进入了循环,则说明不是快乐数。

✨ 这就是今天要分享给大家的全部内容了,我们下期再见!😊

🏠 我在CSDN等你哦!我的主页😍

相关推荐
2401_8532757318 分钟前
ArrayList 源码分析
java·开发语言
zyx没烦恼19 分钟前
【STL】set,multiset,map,multimap的介绍以及使用
开发语言·c++
lb363636363619 分钟前
整数储存形式(c基础)
c语言·开发语言
feifeikon21 分钟前
Python Day5 进阶语法(列表表达式/三元/断言/with-as/异常捕获/字符串方法/lambda函数
开发语言·python
大鲤余28 分钟前
Rust,删除cargo安装的可执行文件
开发语言·后端·rust
浪里个浪的102431 分钟前
【C语言】从3x5矩阵计算前三行平均值并扩展到4x5矩阵
c语言·开发语言·矩阵
MoFe137 分钟前
【.net core】【sqlsugar】字符串拼接+内容去重
java·开发语言·.netcore
笨小古39 分钟前
路径规划——RRT-Connect算法
算法·路径规划·导航
<但凡.1 小时前
编程之路,从0开始:知识补充篇
c语言·数据结构·算法
Envyᥫᩣ1 小时前
深入浅出C#编程语言
开发语言·c#