每日一题:leetcode341.扁平化嵌套列表迭代器

题目描述

在这里插入图片描述

题目分析

这个题目自己大概花了一个小时,虽然是一遍AC,但是速度有点慢,太长时间不写代码导致自己对代码不太敏感,写起来慢腾腾的。

看到这个的想法就是,要用栈来保存列表的迭代器,这样将孩子列表遍历完成后才能重新回到父亲列表中,如果栈为空当然就结束了。

首先是对函数调用的分析,会首先调用hasNext再调用next,这就要求我们如果把后移操作放到hasNext中,那么栈顶就要指向当前位置之前,对于迭代器来说不容易操作,因此我们决定将后移操作放到next函数中

首要要定义栈中保存的迭代器的含义:我的想法是该层列表当前指向元素,这应该是比较符合直觉的,然而就是这种符合直觉的做法导致我的代码要复杂许多。因为这种定义其实是不统一的,栈顶的迭代器是直接可以访问元素的,而下面的迭代器因为保存的是当前元素的位置,所以栈顶访问结束后弹出以后是不能直接访问元素的,必须要执行一次后移操作,这种对栈中元素处理的不统一性导致代码变得复杂:一旦弹出必须要执行一次后移操作。可能这里还不明白为什么变复杂了,我再梳理一下需要进行的步骤:
首先,我们必须在hasNext函数中判断,当前栈顶迭代器需不需要弹出,如果不需要,就要判断当前栈顶迭代器指向的是不是一个整数,如果是,返回真即可,如果不是,需要将子列表的迭代器压栈进行访问,可是子列表有可能为空,因此不能直接访问子列表,同样要对新压入栈的迭代器判断需不需要弹出。如果不需要弹出就是正常操作:要么继续压栈,要么返回。但是如果需要弹出的话,还需要对父亲迭代器进行后移操作,后移以后首先要判断的同样是需不需要弹出。

可以总结一下:

  • 每次后移操作后首先要做的是判断是否需要弹出
  • 每次入栈操作以后要判断是否需要弹出

如果我们直接按照上面的顺序进行操作,将会写出比较复杂的代码(我就是这样),可以看到弹出操作比较频繁,我们可以将其剥离成一个函数

实现代码

class NestedIterator {
public:NestedIterator(vector<NestedInteger> &nestedList) {S.emplace(nestedList.cbegin(), nestedList.cend());}int next() {return (S.top().first++)->getInteger();}bool hasNext() {return !is_empty() && move_to_integer();}
private:using vec_iter = vector<NestedInteger>::const_iterator;stack<pair<vec_iter, vec_iter>> S;bool is_empty() {//检查列表是否为空,应该在每次执行++操作后进行检查//如果为空返回真if (S.empty()) return true;while(S.top().first == S.top().second) {//如果栈顶部的迭代器已经失效,则将其弹出S.pop();if (S.empty()) return true;++S.top().first;}return false;}bool move_to_integer() {//将迭代器指向整数,如果不是整数,则将当前迭代器压入栈//返回假表示后面没有整数,只有空列表while( !( S.top().first -> isInteger()) ) {auto &tp = S.top();//如果当前迭代器指向的不是整数,则得到其指向的列表const auto &lst = tp.first -> getList();if (lst.empty()) {//如果指向的列表为空,则不用处理该列表,直接跳过++tp.first;if (is_empty()) {//如果后面没有有效元素,直接返回假return false;}} else {//如果列表不为空,则将列表的迭代器压栈S.emplace(lst.cbegin(), lst.cend());}}return true;}
};

写代码遇到一个小问题就是我将声明语句放到了表达式中,但是总报错,经过测试发现声明语句不能写在表达式中

AC之后我又去看了一下官方题解,发现思路大同小异,但是发现人家的代码十分简洁,主要的区别在于hasNext函数中题解通过将上面几个函数放到同一个循环里面,通过安排代码的顺序来完成任务:

  • 先判断是否需要弹出,如果需要弹出则弹出后直接continue判断是否非空,然后再次执行循环,这时候就体现出设计的重要性了,题解中栈保存的是下次应该访问的迭代器地址,这就要求父列表迭代器在压入子列表迭代器后同时向后移动一位,因此弹出栈顶迭代器后就不需要再次向后移动了。如果不这样做,弹出后需要先判断栈是否为空,然后再后移,然后再判断是否需要弹出,将导致代码复杂
  • 弹出后判断是否是一个整数,如果是直接返回true,如果不是则不断压栈,直到是一个整数。如果是一个空列表,则重新执行循环以后会弹出,因此不需要做多余的处理。

题解代码

class NestedIterator {
private:// pair 中存储的是列表的当前遍历位置,以及一个尾后迭代器用于判断是否遍历到了列表末尾stack<pair<vector<NestedInteger>::iterator, vector<NestedInteger>::iterator>> stk;public:NestedIterator(vector<NestedInteger> &nestedList) {stk.emplace(nestedList.begin(), nestedList.end());}int next() {// 由于保证调用 next 之前会调用 hasNext,直接返回栈顶列表的当前元素,然后迭代器指向下一个元素return stk.top().first++->getInteger();}bool hasNext() {while (!stk.empty()) {auto &p = stk.top();if (p.first == p.second) { // 遍历到当前列表末尾,出栈stk.pop();continue;}if (p.first->isInteger()) {return true;}// 若当前元素为列表,则将其入栈,且迭代器指向下一个元素auto &lst = p.first++->getList();stk.emplace(lst.begin(), lst.end());}return false;}
};

只能感叹题解代码的巧妙,自己距离这样的水平还很远,要多写多思考。这种模拟题感觉对代码能力还是挺有帮助的,因为工程中代码更多是这样的,注重的是代码的设计效率、是否优雅,而不是算法是否巧妙

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383561.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每日一题:leetcode82. 删除排序链表中的重复元素 II

题目描述 题目分析 这才是正常的中等题难度嘛&#xff0c;昨天的中等题题解我半天看不懂。。。 首先&#xff0c;需要增加一个哑节点&#xff08;操作链表的常规操作&#xff09;&#xff0c;因为有可能删除首节点&#xff0c;我们不想要为首节点添加单独的逻辑。其次&#xf…

每日一题:leetcode456.132模式

题目描述 题目分析 我觉得这道题应该是我做过最难的中等题之一了&#xff0c;这是昨天的每日一题&#xff0c;但是昨天用nlogn的做法做出来以后在看题解&#xff0c;发现有些看不懂&#xff08;觉得题解有点故弄玄虚&#xff09;。然后今天中午又花了一点时间才搞懂&#xff0…

leetcode283.移动零

题目描述 题目分析 在写简单题放松&#xff0c;看到这道题第一个想法是用STL库函数&#xff0c;虽然知道大概要用双指针之类的&#xff0c;但是库函数爽哇。 class Solution { public:void moveZeroes(vector<int>& nums) {stable_sort(nums.begin(), nums.end(), …

每日一题:leetcode61.旋转链表

题目描述 题目分析 很容易发现&#xff0c;如果k是n的整数倍&#xff0c;相当于没有移动。这样直接对k%n使得k在一个可以接受的范围。 因为是顺序移动&#xff0c;各元素之间的相对位置保持不变&#xff0c;所以就想着将链表先变成一个环。然后再移动头指针&#xff0c;最后再…

每日一题:leetcode173.二叉搜索树迭代器

题目描述 题目分析 更加地觉得编程重要的不在于如何写代码&#xff0c;用什么具体的技巧&#xff0c;编码本身只是一种将思维呈现的方式&#xff0c;但是如果思维是不清晰的&#xff0c;那么就算懂得再多的编码的奇技淫巧也是没有什么帮助的。相反&#xff0c;如果有一个清晰的…

leetcode11.盛最多水的容器

题目描述 题目分析 看到题目后第一个想法当然是O(n2)O(n^2)O(n2)的&#xff0c;但是数据范围是3e4&#xff0c;应该会超时&#xff0c;而且这种数据范围也不是让暴力求解的 。 相当于求解∑i<jmax((j−i)∗min(a[i],a[j]))\sum_{i<j}{max((j-i)*min(a[i],a[j]))}∑i<…

每日一题:leetcode190.颠倒二进制位

题目描述 题目分析 题目本身很简单&#xff0c;没觉得有什么技巧可以再进行优化了&#xff0c;觉得位运算是无法打乱相对顺序的&#xff0c;而这里需要进行镜像颠倒的操作。因此就踏实地写了一个循环。 在使用位运算得到每一位的时候&#xff0c;我吸取了经验&#xff0c;用一…

每日一题:leetcode74.搜索二维矩阵

题目描述 题目分析 感觉这是一个放错标签的简单题。题目非常简单&#xff0c;思路应该很明确是二分&#xff0c;我很快写了一个&#xff08;虽然不小心把!打成调试了一会&#xff09;。 class Solution { public:bool searchMatrix(vector<vector<int>>& mat…

每日一题:leetcode90.子集贰

题目描述 题目分析 感觉这道题让自己对枚举排列有了一个更好的认识&#xff0c;感觉自己的这种思路不错。 假设没有重复元素&#xff08;退化成78.子集&#xff09;&#xff0c;我们应该怎么做&#xff1f;初始的时候幂集中只有一个空集&#xff0c;然后对每个元素&#xff0…

每日一题:leetcode1006.笨阶乘

题目描述 题目分析 因为顺序一定且没有括号&#xff0c;所以逻辑很简单。我们要顺序处理的矛盾在于&#xff0c;减号后面会再出现乘法和除法&#xff0c;我们不妨将对乘法和除法用一个临时值进行计算&#xff0c;计算结束后再合并到值里面&#xff0c;一般来讲乘法和除法的处理…

每日一题:leetcode80.删除有序数组中的重复元素贰

题目描述 题目分析 又是一道贴错标签的简单题&#xff0c;很明显的双指针&#xff0c;我的做法是用两个变量保存是否需要记录&#xff0c;官方题解的做法是直接判断&#xff0c;人家的高明一些 class Solution { public:int removeDuplicates(vector<int>& nums) {…

每日一题:leetcode81.搜索旋转排序数组Ⅱ

题目描述 题目分析 不含重复元素的题解&#xff08;leetcode33&#xff09; 这道题也是我们算法课的一道编程题&#xff0c;写完以后发现当时的思路和现在没有什么变化&#xff0c;果然是自己啊。我的想法是先判断区间整体是升序的还是旋转的&#xff0c;如果是升序的就按照正…

Linux创建多个子线程并回收

创建子线程的逻辑相比子进程要更容易理解一些&#xff0c;因为线程没有像进程那样复制很多东西另起炉灶&#xff0c;子线程从传入的开始函数开始运行&#xff0c;但是难点在于传入参数和回收时获取退出状态&#xff0c;因为这两个原本都是void *类型的&#xff0c;而我们在使用…

Qt for Android环境配置

最近想写一个小APP&#xff0c;但是又不想用Android Studio进行开发&#xff0c;想要用C进行开发&#xff0c;听说Qt可以进行Android开发&#xff0c;就想尝试一下&#xff0c;结果花了一天时间来配置环境。。。而且发现windows下配置环境更简单一些&#xff08;我中途还切换到…

Leetcode第284场周赛

绪论 最近发现Leetcode每周的周赛难度挺适合我的&#xff0c;而且时间也比较友好&#xff08;不像Codeforces每次都是半夜&#xff09;。所以连续参加了三周的周赛。这次才想起来应该记录一下自己的参赛历程。一方面是总结经验&#xff0c;另一方面有了记录就更有动力去提升&a…

Leetcode第286场周赛

绪论 上周因为有事没有参加周赛&#xff0c;这周没有错过。这次周赛拿到了人生第一个AK&#xff0c;参加大大小小的比赛这么多次&#xff0c;从来没有AK过&#xff0c;泪目了。 感觉这次比赛的思维难度对我来讲稍高一些&#xff0c;前三道题就花了一个小时&#xff0c;而以往…

第287场周赛

绪论 虽然是上周日参加的比赛&#xff0c;但是这周没有怎么学习&#xff0c;每天就是玩耍。也导致对周赛的总结迟迟没有进行。想着再拖下去下次周赛都要开始了&#xff0c;在这里补一下。 这场比赛总体比上场简单一些&#xff0c;但是最后一道题因为忘记初始化类内变量导致调试…

第288场周赛

绪论 虽然没有AK&#xff0c;但是不知道为什么排名比以前AK了都靠前。可能是因为最后一道题有些难度&#xff0c;缩小了我和大佬之间的差距。最后一个小时写最后一道题&#xff0c;累死累活想了一个贪心遍历的算法&#xff0c;当时是一直RE&#xff0c;后来下来调了调又WA了。 …

Clion远程部署和运行

绪论 作为Clion的忠实粉丝&#xff0c;现在的我的几乎所有的coding都是通过Clion完成。因为需要在服务器上进行开发&#xff0c;又离不开Clion&#xff0c;就了解了如何通过Clion远程部署和开发。 主要是借鉴了博客&#xff1a;使用Clion优雅的完全远程自动同步和远程调试c。如…

Ubuntu install ‘Bash to dock‘

绪论 在Ubuntu环境搭建这篇博客中记录了使用Dash To Dock来配置Ubuntu的菜单项&#xff0c;使得实现macOS一样的效果。为了配置新电脑的环境&#xff0c;我还是想安装这个软件。但是如今在Ubuntu Software中已经找不到这个软件了&#xff0c;我在网上借鉴了一些博客的经验才得…