文章目录
🌈你好呀!我是 山顶风景独好
🎈欢迎踏入我的博客世界,能与您在此邂逅,真是缘分使然!😊
🌸愿您在此停留的每一刻,都沐浴在轻松愉悦的氛围中。
📖这里不仅有丰富的知识和趣味横生的内容等您来探索,更是一个自由交流的平台,期待您留下独特的思考与见解。🌟
🚀让我们一起踏上这段探索与成长的旅程,携手挖掘更多可能,共同进步!💪✨
题目一:两数相除
题目描述
给定两个整数 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等你哦!我的主页😍