迭代器

题库

173. 二叉搜索树迭代器
281. 锯齿迭代器
284. 顶端迭代器
341. 扁平化嵌套列表迭代器
900. RLE迭代器
1286. 字母组合迭代器
1586. 二叉搜索树迭代器 II

173. 二叉搜索树迭代器

实现一个二叉搜索树迭代器类BSTIterator ,表示一个按中序遍历二叉搜索树(BST)的迭代器:
BSTIterator(TreeNode root) 初始化 BSTIterator 类的一个对象。BST 的根节点 root 会作为构造函数的一部分给出。指针应初始化为一个不存在于 BST 中的数字,且该数字小于 BST 中的任何元素。
boolean hasNext() 如果向指针右侧遍历存在数字,则返回 true ;否则返回 false 。
int next()将指针向右移动,然后返回指针处的数字。
注意,指针初始化为一个不存在于 BST 中的数字,所以对 next() 的首次调用将返回 BST 中的最小元素。

你可以假设 next() 调用总是有效的,也就是说,当调用 next() 时,BST 的中序遍历中至少存在一个下一个数字。

输入
["BSTIterator", "next", "next", "hasNext", "next", "hasNext", "next", "hasNext", "next", "hasNext"]
[[[7, 3, 15, null, null, 9, 20]], [], [], [], [], [], [], [], [], []]
输出
[null, 3, 7, true, 9, true, 15, true, 20, false]

解释
BSTIterator bSTIterator = new BSTIterator([7, 3, 15, null, null, 9, 20]);
bSTIterator.next();    // 返回 3
bSTIterator.next();    // 返回 7
bSTIterator.hasNext(); // 返回 True
bSTIterator.next();    // 返回 9
bSTIterator.hasNext(); // 返回 True
bSTIterator.next();    // 返回 15
bSTIterator.hasNext(); // 返回 True
bSTIterator.next();    // 返回 20
bSTIterator.hasNext(); // 返回 False
class BSTIterator {
    private int idx;
    private List<Integer> arr;

    public BSTIterator(TreeNode root) {
        idx = 0;
        arr = new ArrayList<Integer>();
        inorderTraversal(root, arr);
    }

    public int next() {
        return arr.get(idx++);
    }

    public boolean hasNext() {
        return idx < arr.size();
    }

    private void inorderTraversal(TreeNode root, List<Integer> arr) {
        if (root == null) {
            return;
        }
        inorderTraversal(root.left, arr);
        arr.add(root.val);
        inorderTraversal(root.right, arr);
    }
}

281.锯齿迭代器

给出两个一维的向量,请你实现一个迭代器,交替返回它们中间的元素。

示例:
输入:
v1 = [1,2]
v2 = [3,4,5,6] 
输出: [1,3,2,4,5,6]

解析: 通过连续调用 next 函数直到 hasNext 函数返回 false,
     next 函数返回值的次序应依次为: [1,3,2,4,5,6]。

拓展:假如给你 k 个一维向量呢?你的代码在这种情况下的扩展性又会如何呢?

拓展声明:
 “锯齿” 顺序对于 k > 2 的情况定义可能会有些歧义。所以,假如你觉得 “锯齿” 这个表述不妥,也可以认为这是一种 “循环”。例如:
输入:
[1,2,3]
[4,5,6,7]
[8,9]
输出: [1,4,8,2,5,9,3,6,7].
public class ZigzagIterator {
    List<List<Integer>> data = new ArrayList<>(); //所有数据
    int size; //数据列表的总数
    int cur;  //当前遍历到的list的序号
    List<Integer> index = new ArrayList(); //每个list中当前遍历到的位置index

    public ZigzagIterator(List<Integer> v1, List<Integer> v2) {
        data.add(v1);
        data.add(v2);
        size = 2; //目前只有两个列表,可扩展为k个
        cur = 0;  //从第0个list开始遍历
        index.add(0);
        index.add(0);
    }

    public int next() {
        int ans = data.get(cur).get(index.get(cur)); //取出当前的数据
        index.set(cur,index.get(cur)+1); //更改位置到下一个数据,有效性有hasNext来保证
        cur = (cur+1) % size;
        return ans;
    }

    public boolean hasNext() {
        int start = cur; //保存目前的序号,用来判断是否所有list都已经遍历到了最后一个位置
        while(index.get(cur)==data.get(cur).size()){
            cur = (cur+1) % size;

            /**
            运行到下一个if语句,说明所有的list都在最后一个位置,cur回到了最开始进入while循环的位置
            此时,所有数据都已经遍历完成,返回false
            如果没有这一句,会进入无限循环
            */
            if(cur == start) return false; 
        }
        return true;
    }
}

/**
 * Your ZigzagIterator object will be instantiated and called as such:
 * ZigzagIterator i = new ZigzagIterator(v1, v2);
 * while (i.hasNext()) v[f()] = i.next();
 */

284. 顶端迭代器

给定一个迭代器类的接口,接口包含两个方法: next() 和 hasNext()。设计并实现一个支持 peek() 操作的顶端迭代器 – 其本质就是把原本应由 next() 方法返回的元素 peek() 出来。

示例:
假设迭代器被初始化为列表 [1,2,3]。
调用 next() 返回 1,得到列表中的第一个元素。
现在调用 peek() 返回 2,下一个元素。在此之后调用 next() 仍然返回 2。
最后一次调用 next() 返回 3,末尾元素。在此之后调用 hasNext() 应该返回 false。
进阶:你将如何拓展你的设计?使之变得通用化,从而适应所有的类型,而不只是整数型?
 class PeekingIterator implements Iterator<Integer> {

        private LinkedList<Integer> queue;

        public PeekingIterator(Iterator<Integer> iterator) {
            queue = new LinkedList<>();
            while (iterator.hasNext()) {
                queue.add(iterator.next());
            }
        }

        public Integer peek() {
            return queue.peek();
        }

        @Override
        public Integer next() {
            return queue.poll();
        }

        @Override
        public boolean hasNext() {
            return !queue.isEmpty();
        }
}

341.扁平化嵌套列表迭代器

给你一个嵌套的整型列表。请你设计一个迭代器,使其能够遍历这个整型列表中的所有整数。

列表中的每一项或者为一个整数,或者是另一个列表。其中列表的元素也可能是整数或是其他列表。

输入: [[1,1],2,[1,1]]
输出: [1,1,2,1,1]
解释: 通过重复调用 next 直到 hasNext 返回 false,next 返回的元素的顺序应该是: [1,1,2,1,1]。
public class NestedIterator implements Iterator<Integer> {
    private LinkedList<NestedInteger> list;

    public NestedIterator(List<NestedInteger> nestedList) {
        list = new LinkedList<>(nestedList);
    }

    @Override
    public Integer next() {
        return list.remove(0).getInteger();
    }

    @Override
    public boolean hasNext() {
        while(!list.isEmpty() && !list.get(0).isInteger()){
            List<NestedInteger> first = list.remove(0).getList();
            for(int i = first.size() - 1; i >= 0; i--){
                list.addFirst(first.get(i));
            }
        }   
        return !list.isEmpty();
    }
}

public class NestedIterator implements Iterator<Integer> {
    private List<Integer> vals;
    private Iterator<Integer> cur;

    public NestedIterator(List<NestedInteger> nestedList) {
        vals = new ArrayList<Integer>();
        dfs(nestedList);
        cur = vals.iterator();
    }

    @Override
    public Integer next() {
        return cur.next();
    }

    @Override
    public boolean hasNext() {
        return cur.hasNext();
    }

    private void dfs(List<NestedInteger> nestedList) {
        for (NestedInteger nest : nestedList) {
            if (nest.isInteger()) {
                vals.add(nest.getInteger());
            } else {
                dfs(nest.getList());
            }
        }
    }
}

900. RLE迭代器

编写一个遍历游程编码序列的迭代器。

迭代器由 RLEIterator(int[] A) 初始化,其中 A 是某个序列的游程编码。更具体地,对于所有偶数 i,A[i] 告诉我们在序列中重复非负整数值 A[i + 1] 的次数。

迭代器支持一个函数:next(int n),它耗尽接下来的 n 个元素(n >= 1)并返回以这种方式耗去的最后一个元素。如果没有剩余的元素可供耗尽,则 next 返回 -1 。

例如,我们以 A = [3,8,0,9,2,5] 开始,这是序列 [8,8,8,5,5] 的游程编码。这是因为该序列可以读作 “三个八,零个九,两个五”。

示例:
输入:["RLEIterator","next","next","next","next"], [[[3,8,0,9,2,5]],[2],[1],[1],[2]]
输出:[null,8,8,5,-1]
解释:
RLEIterator 由 RLEIterator([3,8,0,9,2,5]) 初始化。
这映射到序列 [8,8,8,5,5]。
然后调用 RLEIterator.next 4次。
.next(2) 耗去序列的 2 个项,返回 8。现在剩下的序列是 [8, 5, 5]。
.next(1) 耗去序列的 1 个项,返回 8。现在剩下的序列是 [5, 5]。
.next(1) 耗去序列的 1 个项,返回 5。现在剩下的序列是 [5]。
.next(2) 耗去序列的 2 个项,返回 -1。 这是由于第一个被耗去的项是 5,
但第二个项并不存在。由于最后一个要耗去的项不存在,我们返回 -1。
class RLEIterator {
   int[] A;
   int i, q;

   public RLEIterator(int[] A) {
       this.A = A;
       i = q = 0;
   }

   public int next(int n) {
       while (i < A.length) {
           if (q + n > A[i]) {
               n -= A[i] - q;
               q = 0;
               i += 2;
           } else {
               q += n;
               return A[i+1];
           }
       }

       return -1;
   }
}

1286. 字母组合迭代器

请你设计一个迭代器类,包括以下内容:

一个构造函数,输入参数包括:一个 有序且字符唯一 的字符串 characters(该字符串只包含小写英文字母)和一个数字 combinationLength 。
函数 next() ,按 字典序 返回长度为 combinationLength 的下一个字母组合。
函数 hasNext() ,只有存在长度为 combinationLength 的下一个字母组合时,才返回 True;否则,返回 False。

示例:
CombinationIterator iterator = new CombinationIterator("abc", 2); // 创建迭代器 iterator
iterator.next(); // 返回 "ab"
iterator.hasNext(); // 返回 true
iterator.next(); // 返回 "ac"
iterator.hasNext(); // 返回 true
iterator.next(); // 返回 "bc"
iterator.hasNext(); // 返回 false
class CombinationIterator {
    Queue<String> combinations;
    public CombinationIterator(String characters, int combinationLength) {
        combinations = new LinkedList<>();
        boolean[] visited = new boolean[characters.length()];
        backtrack(characters, combinationLength, new StringBuilder(), visited);
    }

    private void backtrack(String characters, int combinationLength, StringBuilder combination, boolean[] visited) {
        if (combination.length() == combinationLength) {
            combinations.add(combination.toString());
            return;
        }
        for (int i = 0; i < characters.length(); i++) {
            if (!visited[i] && (combination.length() == 0 || characters.charAt(i) > combination.charAt(combination.length() - 1))) {
                visited[i] = true;
                combination.append(characters.charAt(i));
                backtrack(characters, combinationLength, combination, visited);
                visited[i] = false;
                combination.deleteCharAt(combination.length() - 1);
            }
        }
    }

    public String next() {
        return combinations.poll();
    }

    public boolean hasNext() {
        return !combinations.isEmpty();
    }
}
/**
 * Your CombinationIterator object will be instantiated and called as such:
 * CombinationIterator obj = new CombinationIterator(characters, combinationLength);
 * String param_1 = obj.next();
 * boolean param_2 = obj.hasNext();
 */

1586. 二叉搜索树迭代器 II

实现二叉搜索树(BST)的中序遍历迭代器 BSTIterator 类:

BSTIterator(TreeNode root) 初始化 BSTIterator 类的实例。二叉搜索树的根节点 root 作为构造函数的参数传入。内部指针使用一个不存在于树中且小于树中任意值的数值来初始化。
boolean hasNext() 如果当前指针在中序遍历序列中,存在右侧数值,返回 true ,否则返回 false 。
int next() 将指针在中序遍历序列中向右移动,然后返回移动后指针所指数值。
boolean hasPrev() 如果当前指针在中序遍历序列中,存在左侧数值,返回 true ,否则返回 false 。
int prev() 将指针在中序遍历序列中向左移动,然后返回移动后指针所指数值。
注意,虽然我们使用树中不存在的最小值来初始化内部指针,第一次调用 next() 需要返回二叉搜索树中最小的元素。

你可以假设 next() 和 prev() 的调用总是有效的。即,当 next()/prev() 被调用的时候,在中序遍历序列中一定存在下一个/上一个元素。

进阶:你可以不提前遍历树中的值来解决问题吗?

输入
["BSTIterator", "next", "next", "prev", "next", "hasNext", "next", "next", "next", "hasNext", "hasPrev", "prev", "prev"]
[[[7, 3, 15, null, null, 9, 20]], [null], [null], [null], [null], [null], [null], [null], [null], [null], [null], [null], [null]]
输出
[null, 3, 7, 3, 7, true, 9, 15, 20, false, true, 15, 9]

解释
// 划线的元素表示指针当前的位置。
BSTIterator bSTIterator = new BSTIterator([7, 3, 15, null, null, 9, 20]); // 当前状态为 <u> </u> [3, 7, 9, 15, 20]
bSTIterator.next(); // 状态变为 [<u>3</u>, 7, 9, 15, 20], 返回 3
bSTIterator.next(); // 状态变为 [3, <u>7</u>, 9, 15, 20], 返回 7
bSTIterator.prev(); // 状态变为 [<u>3</u>, 7, 9, 15, 20], 返回 3
bSTIterator.next(); // 状态变为 [3, <u>7</u>, 9, 15, 20], 返回 7
bSTIterator.hasNext(); // 返回 true
bSTIterator.next(); // 状态变为 [3, 7, <u>9</u>, 15, 20], 返回 9
bSTIterator.next(); // 状态变为 [3, 7, 9, <u>15</u>, 20], 返回 15
bSTIterator.next(); // 状态变为 [3, 7, 9, 15, <u>20</u>], 返回 20
bSTIterator.hasNext(); // 返回 false
bSTIterator.hasPrev(); // 返回 true
bSTIterator.prev(); // 状态变为 [3, 7, 9, <u>15</u>, 20], 返回 15
bSTIterator.prev(); // 状态变为 [3, 7, <u>9</u>, 15, 20], 返回 9
class BSTIterator {

    //始终指向双向链表头节点
    private TreeNode dummyNode = new TreeNode(Integer.MIN_VALUE); 

    //迭代器当前所处节点
    private TreeNode current;

    //用于原地构造双向链表
    private TreeNode prev;
    
    public BSTIterator(TreeNode root) {
        prev = dummyNode;

        //中序遍历原地构造双向链表
        if(root != null) {
            inorder(root);
        }

        current = dummyNode;
        

    }
    
    public boolean hasNext() {
        return current.right != null;
    }
    
    public int next() {
        current = current.right;
        return current.val;
    }
    
    public boolean hasPrev() {
        return current.left != null && current.left != dummyNode;
    }
    
    public int prev() {
        current = current.left;
        return current.val;
    }

    //原地构造双向链表
    private void inorder(TreeNode root) {
        if(root == null) return;
        inorder(root.left);
        prev.right = root;
        root.left = prev;
        prev = root;
        inorder(root.right);

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值