【刷题】优选算法

时间:2024-11-08 07:56:45

优选算法

双指针

202. 快乐数

链接:. - 力扣(LeetCode)

【思路】

第一个实例是快乐数,因为会变为1且不断是1的循环

第二个实例不可能为1,因为会陷入一个没有1的循环

根据两个实例和鸽巢原理可以发现不断的平方和最终都会形成环,所以我们可以联想到用快慢指针,慢指针走一步,快指针走两步,最终会在环相遇,判断相遇时是否为1。

    //‘平分和’操作
    int squareSum(int num)
    {
        int sum = 0;
        while(num)
        {
            int unit = num % 10;
            num /= 10;
            sum += unit*unit;
        }
        return sum;
    }

    bool isHappy(int n) 
    {
        //快慢指针
        int fast = n, slow = n;

        //相遇才停下
        do 
        {
            //慢指针操作一次
            slow = squareSum(slow);
            //快指针操作两次
            fast = squareSum(squareSum(fast));
        } while(fast != slow);

        //相遇的值等于1才行
        return slow == 1;
    }

11. 盛最多水的容器

链接:. - 力扣(LeetCode)

【思路】

容量 = 底(下标相减) * 高(数组元素较小值)

如图,我们先算出最左边(1)和最右边(7)围起来的容量,然后,7不动,1继续和7的左边3,8,4...遍历算出容量,你会发现底是不断缩短的,同时高一直都是1,因为高只有两种情况,比它小或和它相等,所以1和7左边的值算出来的容量都是比1和7的容量小的,因为底在不断变小同时高可能不变也可能变小。

所以可以得出结论,每次算完容量后,元素较小的直接移动,不用遍历其他结果。

    int maxArea(vector<int>& height) 
    {
        int head = 0, tail = height.size() - 1;

        int final_cap = 0;
        while(head < tail)
        {
            //计算容量,保留较大值
            int capacity = (tail - head) * min(height[head], height[tail]);   
            final_cap = max(final_cap, capacity);

            //思路的推断移动高度小的一方
            if(height[head] < height[tail])
            {
                ++head;
            }
            else
            {
                --tail;
            }
        }
        
        return final_cap;
    }

611. 有效三角形的个数

链接:. - 力扣(LeetCode)

【思路】

判断三角形:最长边小于其它边之和。

先排序获取单调性配合双指针解决问题。

先固定最长边,然后先从剩下的区间两端作为另外两条边,2+9>10,同时因为单调性,left的右边都比left大,所以right和左边任意一条组合都大于10,计算完组合后, right--继续找下一条边,此时2+5<10,因为单调性,right的左边都比right小,所以left和right左边的任意一条组合都小于10,排除left,left++, 继续找下一条边,这样一个区间找完就视为完成一次最大边的固定,需要固定下一条最大边,直到固定完所有最大边,最后一条最大边是倒数第三条,因为还剩最后两条构不成三角形。

    int triangleNumber(vector<int>& nums) 
    {
        //排序获取单调性
        sort(nums.begin(), nums.end());

        //固定一个最大边
        int ret = 0;
        for(int i = nums.size() - 1; i >= 2; --i)
        {
            //将区间两端作为两条边,不断缩小
            int left = 0, right = i - 1;
            while(left < right)
            {
                if(nums[left] + nums[right] > nums[i])
                {
                    ret += right - left;
                    --right;
                }
                else
                {
                    ++left;
                }
            }
        }

        return ret;
    }

LCR 179. 查找总价格为目标值的两个商品

链接:. - 力扣(LeetCode)