Leetcode错题集-Q341-扁平化嵌套列表迭代器

原题描述

LeetCode第341题 扁平化嵌套列表迭代器
难度:中等
给你一个嵌套的整型列表。请你设计一个迭代器,使其能够遍历这个整型列表中的所有整数。
列表中的每一项或者为一个整数,或者是另一个列表。其中列表的元素也可能是整数或是其他列表。

相关类

// This is the interface that allows for creating nested lists.
// You should not implement it, or speculate about its implementation
public interface NestedInteger {
   // @return true if this NestedInteger holds a single integer, rather than a nested list.
   public boolean isInteger();
    
   // @return the single integer that this NestedInteger holds, if it holds a single integer
   // Return null if this NestedInteger holds a nested list
   public Integer getInteger();

   // @return the nested list that this NestedInteger holds, if it holds a nested list
   // Return null if this NestedInteger holds a single integer
   public List<NestedInteger> getList();
}

我的思路

nestedList即会返回整数,也会返回列表。对于整数,我们可以按照List<integer>的方式设计迭代器。而对于列表,我的思路是为列表创建创建一个迭代器对象,通过递归调用对象的next()hasNext()方法得到结果。

因此,其中的难点在于hasNext()方法。首先,我们需要在迭代器中维护一个下标。

  1. 如果下标超出List的长度,可以直接返回fasle;
  2. 如果下标所在位置的NestedInteger对象持有一个整数,可以直接返回true;
  3. 如果以上条件均不满足,则下标所在位置的NestedInteger对象持有一个列表,则需要为其创建一个NestedIterator对象:
    3.1. 如果存在一个迭代器对象,说明我们不是第一次停留在该列表上,此时应该调用迭代器对象的hasNext()方法:
        3.1.1如果返回为true,说明下标位置处的列表中有未遍历的元素,可以直接向外返回true;
        3.1.2如果返回为false,说明下标位置处的列表已经完全遍历,此时需要移动下标,同时将迭代器对象对象置空,但我们并不知道后续数据的情况,因此我们需要重新调用(也就是递归调用)本地迭代器的hasNext()方法;
    3.2. 如果不存在一个迭代器对象,则创建一个迭代器对象(当然,如果列表本身长度为0,则可以直接跳过),由于我们并不知道列表内部结构,因此需要迭代器对象的hasNext()方法,并将结果返回。

next()方法的设计相对简单。

  1. 如果下标所在位置的NestedInteger对象持有一个整数,可以直接返回该整数;
  2. 如果下标所在位置的NestedInteger对象持有一个列表,可以调用迭代器的next()方法即可。

我的尝试

第一次

public class NestedIterator implements Iterator<Integer> {

    private List<NestedInteger> nestedList;
    private int index;
    private NestedIterator innerIterator;

    public NestedIterator(List<NestedInteger> nestedList) {
        this.nestedList = nestedList;
        this.index = 0;
    }

    @Override
    public Integer next() {
        if(this.nestedList.get(this.index).isInteger()){
            return this.nestedList.get(this.index++).getInteger();
        }
        return this.innerIterator.next();
        
    }
    
    @Override
    public boolean hasNext() {
        if(this.index>=this.nestedList.size()){
            return false;
        }
        if(this.nestedList.get(this.index).isInteger()){
            return true;
        }
        if(this.innerIterator!=null && this.innerIterator.hasNext()){
            return true;
        }else if (this.innerIterator==null){
            List<NestedInteger> innerList = this.nestedList.get(this.index).getList();
            if(innerList!=null && innerList.size()>0){
                this.innerIterator = new NestedIterator(innerList);
                return this.innerIterator.hasNext();
            }
        }
        this.index ++;
        this.innerIterator = null;
        return this.hasNext();
    }
}

提交结果:解答错误
输入:[[],[[]],-4,[[[]]],[[],2,[[]],[[-3],1],[[],-1]]]
输出:[]
预期:[-4,2,-3,1,-1]

分析原因

这个测试样例过于复杂,可以先看一个简单的。
输入:[[[]],1]
输出:[]
预期:[1]

在index=0时,其指向的NestedInteger对象持有一个列表[[]],其长度为1。而此时innerIterator为空,我们会为其实例化一个NestedIterator对象,并将列表[[]]传入,并调用innerIterator的hasNext()方法。
在innerIterator中,innerIterator.index=0时,其指向的NestedInteger对象持有一个列表[],其长度为0,因此innerIterator的hasNext()方法会返回false,这也导致了上一层的hasNext()方法返回false,进而造成结果出错。

解决思路

这里的本质是3.2.2处,对当前迭代器对象hasNext()方法的返回值,应当按照3.1.1与3.1.2的方式处理,而不是直接返回。
因此,正确的思路如下:

  1. 如果下标超出List的长度,可以直接返回fasle;
  2. 如果下标所在位置的NestedInteger对象持有一个整数,可以直接返回true;
  3. 如果以上条件军部满足,则下标所在位置的NestedInteger对象持有一个列表,则需要为其创建一个NestedIterator对象:
    3.1. 如果不存在一个迭代器对象,则创建一个迭代器对象(当然,如果列表本身长度为0,则可以直接跳过);
    3.2. 调用迭代器对象的hasNext()方法:
        3.1.1如果返回为true,说明下标位置处的列表中有未遍历的元素,可以直接向外返回true;
        3.1.2如果返回为false,说明下标位置处的列表已经完全遍历,此时需要移动下标,同时将迭代器对象对象置空,但我们并不知道后续数据的情况,因此我们需要重新调用(也就是递归调用)本地迭代器的hasNext()方法;

第二次

public class NestedIterator implements Iterator<Integer> {

    private List<NestedInteger> nestedList;
    private int index;
    private NestedIterator innerIterator;

    public NestedIterator(List<NestedInteger> nestedList) {
        this.nestedList = nestedList;
        this.index = 0;
    }

    @Override
    public Integer next() {
        if(this.nestedList.get(this.index).isInteger()){
            this.index ++;
            return this.nestedList.get(this.index-1).getInteger();
        }
        return this.innerIterator.next();
        
    }

    @Override
    public boolean hasNext() {
        if(this.index>=this.nestedList.size()){
            return false;
        }
        if(this.nestedList.get(this.index).isInteger()){
            return true;
        }
        List<NestedInteger> innerList = this.nestedList.get(this.index).getList();
        if(innerList!=null && innerList.size()>0){
            if (this.innerIterator==null){
                this.innerIterator = new NestedIterator(innerList);
            }
            if (this.innerIterator.hasNext()){
                return true;
            }
        }
        this.index ++;
        this.innerIterator = null;
        return this.hasNext();
    }
}

提交结果:通过

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值