C++ 快乐数 —— 优先算法(双指针思想)

目录

1. 题目解析 

2. 算法原理

3. 代码实现


 快乐数

1. 题目解析 

 根据题目可知:快乐数就是对于一个数,它的每位上的数字的平方和,最终结果是到1。

 2. 算法原理

从题目解析上两个图对比来看

所以可以抽象成环形链表的问题,解法就用快慢双指针。(注:这里双指针是一种思想,并不是真正意义上要定义两个指针,用一个数看作成一个指针来控制)

解法思想:

  1. 定义快慢指针(fast,slow)
  2. 慢指针每次向后移动一步,快指针每次向后移动两步。
  3. 判断相遇时的值即可,是1就是快乐数,不是1就不是快乐数(注:通过题目给予的定义来看是一定会相遇的)。

题外话:快慢双指针解决环形链表时,是通过判断两个指针是否相遇即可。 

为快乐数的情况:

 不为快乐数的情况:

 

 

  

3. 代码实现

 根据上述分析:

class Solution {
public:
    //求平方和后续会用的频繁
    //因此把它封装到类里面,默认内联函数
    //减少函数调用的开销
    int bitSum(int n) // 返回n这个数的每一位数的平方相加的和
    {
        int sum = 0;
        // 先把最后一个数取出来,平方一下放到一个变量里,然后干掉最后一位数
        while (n) {
            int t = n % 10;
            sum += t * t;
            n /= 10;
        }

        return sum;
    }

    bool isHappy(int n) {
        // 抽象成快慢指针的解法
        int fast = bitSum(n), slow = n;  
        //因为一定是会相遇的,
        //先让fast走一步,以防止进入不了while循环
        while (slow != fast) {
            //fast要比slow快
            slow = bitSum(slow);
            fast = bitSum(bitSum(fast));
        }
        return slow == 1;   //返回判断是否等于1
    }
};

链接跳转:快乐数

提交记录:

制作不易,若有不足之处或出问题的地方,请各位大佬多多指教 ,感谢大家的阅读支持!!!  

### 关于C++双指针算法的实现 在C++编程中,双指针是一种常见的算法设计模式,主要用于解决涉及组、链表或其他线性据结构的问题。它通常通过两个索引或变量来遍历据集的不同部分,从而优化时间复杂度。 #### 双指针的基本概念 双指针并不总是严格意义上的指针类型(`*`),它可以是组下标或者其他形式的迭代器[^2]。其核心思想在于利用两个位置标记协同工作,减少不必要的重复计算。 以下是几个典型的双指针应用场景及其对应的代码示例: --- #### 示例一:移除指定值后的组长度 给定一个整组 `nums` 和一个目标值 `val`,删除所有等于该值的元素并返回新组的长度。 ```cpp #include <vector> using namespace std; int removeElement(vector<int>& nums, int val) { int slow = 0; // 慢指针用于记录有效元素的位置 for (int fast = 0; fast < nums.size(); ++fast) { // 快指针用于扫描整个组 if (nums[fast] != val) { nums[slow++] = nums[fast]; // 将不等于val的元素移动到前面 } } return slow; } ``` 上述代码展示了如何使用快慢指针技术高效地原地修改组[^1]。 --- #### 示例二:寻找有序组中的两之和 假设输入是一个升序排列的整组 `numbers` 和一个目标值 `target`,找到两个使得它们相加的结果为目标值,并返回这两个的索引。 ```cpp #include <vector> using namespace std; vector<int> twoSum(const vector<int>& numbers, int target) { int left = 0, right = numbers.size() - 1; // 定义左右指针 while (left < right) { int sum = numbers[left] + numbers[right]; if (sum == target) { return {left + 1, right + 1}; // 返回结果(注意题目可能要求从1开始计) } else if (sum < target) { ++left; // 如果总和小于目标,则右移左指针增大值 } else { --right; // 如果总和大于目标,则左移右指针减小值 } } return {}; // 若无解则返回空集合 } ``` 此代码片段体现了双指针法在处理排序组时的优势——无需额外空间即可完成操作。 --- #### 示例三:“快乐”的判断逻辑 对于任意正整 n ,如果反复替换为各位字平方和最终会进入循环或者达到固定点1,则称为“快乐”。虽然这里并未直接采用传统意义下的指针对象,但依然遵循了双指针的核心理念即设置两个速度不同的游标逐步逼近结论。 ```cpp bool isHappy(int n) { auto get_next = [](int num)->int{ int total_sum=0; while(num>0){ int d=num%10; num /=10 ; total_sum +=d*d; } return total_sum; }; int slow=n , fast=get_next(n); while(fast!=1 && slow!=fast ){ slow=get_next(slow); // 移动一次 fast=get_next(get_next(fast)); // 移动两次 } return fast==1 ; // 判断条件成立与否 } ``` 在这里,“慢跑者”每次只前进一步而“快速选手”每轮跳跃两步直至相遇为止。 --- ### 总结 以上三个例子分别演示了不同类型的双指针应用方式,无论是实际物理地址上的指针还是抽象层面的概念化表达均能体现出这一技巧的强大功能与灵活性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值