LintCode数据结构题总结

Lintcode数据结构有这么一些题目:


495. Implement Stack

用任意的数据结构实现一个栈,我是用List实现的,记得写的时候写成List<Integer> array = new ArrayList<Integer>(); 因为List只是Interface,而实现List接口的有多个类,其中一种就是ArrayList,然后记住List的三种操作是add/remove/get,ArrayList可以通过remove操作删除任意下标的元素,可以通过get获得任意下标的元素,可以通过add在末尾添加元素。


40. Implement Queue by Two Stacks

用两个栈stack1、stack2 来实现队列,记得java中自带的Stack是这么写的Stack<Integer>。

push操作:就直接将元素加到stack1上。

pop操作:如果stack2里面有元素,就直接把stack2里的元素pop出来。如果stack2里面没有元素,就把stack1里的所有元素转移到stack2中,然后再把stack2里的元素pop出来。

top操作:类似于pop操作,不再赘述。


12. Min Stack

要求实现一个栈,这个栈除了push和pop操作外,还要有一个min操作,可以随时拿出stack里面的最小值。我是用2个栈实现的,一个栈用于存储基本元素,另一个栈用于存当前的最小值。

A)第一种方案比较耗空间,stack里面有n个元素,那minStack里面也得有n个元素。这样每次push的时候,minStack里都存进一个当前的最小值;每次pop的时候,当前的最小值也同时pop出来了。如下图所示:


B)第二种方案比较省空间,minStack的上层元素比下层元素要小,minStack是一个最小元素在上面的栈。

每次push的时候,只有当新元素 ≤ minStack里最小的元素(即minStack的顶部元素)的时候,我才把新元素也push进minStack。

每次pop的时候,我先pop 主stack的top元素,而对于minStack的top元素,只有当stack里的top元素和minStack的top元素相等时,我才把minStack的top元素也pop掉。如下所示:


记得判断元素相等的时候用equals函数!!!如果在这里直接用==判断的话,他是判断地址而不是判断值


494. Implement Stack by Two Queues

用两个队列来实现栈,记得java中队列得这样声明才行:Queue<Integer> q1 = new LinkedList<Integer>();  Queue是Interface,实现Queue的方式之一是LinkedList

然后java自带的Queue有两种操作:往队列为部加元素是offer(),获得队列头部元素并同时删除队列头部元素的操作是poll()

我们用两个队列q1和q2来实现,其中q1是存元素的主队列,q2是辅助操作队列

实现栈的push操作时,直接往q1里面添加元素就行

实现栈的pop操作时,因为我要pop的是q1的最末尾的元素,所以我就先把q1的前n-1个元素放到q2,然后再把q1唯一的元素给弹出来。然后再把q2的元素放回q1(或者直接交换q1和q2的引用)

实现top操作和pop操作类似。

实现empty操作时,就判断q1和q2的大小是否为0


492. Implement Queue by Linked List

用链表实现一个Queue,要求有如下两个功能:

enqueue(item). Put a new item in the queue. 

dequeue(). Move the first item out of the queue, return it.

实现方法就用头尾指针,进队的时候将尾指针的值设置为新元素,然后尾指针后面添加一个新的尾指针。出队的时候在头结点后面删除一个节点。纯粹考链表基本操作。

class Node {
    public int val;
    public Node next;
    public Node(int n) {
        val = n;
        next = null;
    }
}

public class Queue {
    public Node first, last;
    public Queue() {
        first = new Node(-1);
        last = new Node(-1);
        first.next = last;
    }

    public void enqueue(int item) {
        Node tmp = new Node(-1);
        last.val = item;
        last.next = tmp;
        last = tmp;
    }

    public int dequeue() {
        int tmp = first.next.val;
        first.next = first.next.next;
        return tmp;
    }
}

493. Implement Queue by Linked List II

多了几个操作,push front和pop back操作。

  1. push_front(item). Add a new item to the front of queue.
  2. push_back(item). Add a new item to the back of the queue.
  3. pop_front(). Move the first item out of the queue, return it.
  4. pop_back(). Move the last item out of the queue, return it.
如果用双向链表的话,四个操作都能在O(1)时间复杂度内完成,如果只用单向链表,则pop_back操作要O(n).我是用单向链表完成的:

class Node {
    public int val;
    public Node next;
    public Node(int n) {
        val = n;
        next = null;
    }
}
public class Dequeue {
    private Node first, last;
    public Dequeue() {
        // do initialize if necessary
        first = new Node(-1);
        last = new Node(-1);
        first.next = last;
    }

    public void push_front(int item) {
        Node tmp = new Node(item);
        tmp.next = first.next;
        first.next = tmp;
    }

    public void push_back(int item) {
        Node tmp = new Node(-1);
        last.val = item;
        last.next = tmp;
        last = tmp;
    }

    public int pop_front() {
        int tmp = first.next.val;
        first.next = first.next.next;
        return tmp;
    }

    public int pop_back() {
        Node p = first;
        while (p.next != last) {
            p = p.next;
        }
        int tmp = p.val;
        p.val = -1;
        last = p;
        return tmp;
    }
}

229. Stack Sorting

对一个栈进行排序,要求只能用到一个额外的辅助栈,

| |
|3|
|1|
|2|
|4|
 -
排序完后变这样:

| |
|4|
|3|
|2|
|1|
 -
我是用一个辅助栈tmp搞定的。

借鉴冒泡排序的算法,我第一趟把原栈中最大的元素放入辅助栈,第二趟把原栈中第二大的元素沉入辅助栈,以此类推。

每趟遍历的目的就是为了找到原栈中当前的最大值。

可设置一个变量mid,用于记录那一趟遍历所找到的“当前”最大值。

在每一趟遍历中,借助那个变量mid找更新原栈中的最大值,同时把所有比mid小的元素都倒腾到辅助栈中。这个时候mid存入了当前的最大值,然后所有其它元素都在辅助栈中,原栈是空的。然后再把辅助栈中的所有比mid小的元素移动回原栈,再把mid移入辅助栈。这样就保持了辅助栈的下面的元素都比上面的大。

记住要用一个遍历count来处理多个元素相同的情况。然后把count数目个mid元素沉入辅助栈。

然后继续处理下一个原栈的栈顶元素,最后直到原栈中的所有元素都被转移到有序栈中!


总而言之,算法的思想就是借鉴了冒泡排序,借用一个辅助栈和一个中间变量,每趟都把栈的最大元素沉入辅助栈的下面。然后注意的一点就是如何处理存在多个相等元素的问题。

Time: O(N^2), Space: O(N)。算法直观的运行效果如下:


代码如下:

    public void stackSorting(Stack<Integer> stack) {
        // 辅助栈
        Stack<Integer> tmp = new Stack<Integer>();
        
        int mid = Integer.MIN_VALUE;
        // 循环条件:当整个stack还没有排好序时
        while (!stack.empty()) {
            int count = 1;
            if (!stack.empty()) {
                mid = stack.pop();
            }
            // 把stack掏空,找出当前stack的最大值
            while (!stack.empty()) {
                if (stack.peek() <= mid) {
                    tmp.push(stack.pop());
                } else {
                    tmp.push(mid);
                    mid = stack.pop();
                }
            }
            // 复原stack
            while (!tmp.empty() && mid >= tmp.peek()) {
                // 处理相等元素的情况
                if (tmp.peek().equals(mid)) {
                    count++;
                    tmp.pop();
                    continue;
                }
                stack.push(tmp.pop());
            }
            // 更新全局最大值
            for (int i = 1; i <= count; i++) {
                tmp.push(mid);
            }
        }
        
        while (!tmp.empty()) {
            stack.push(tmp.pop());
        }
    }

128. Hash Function

要求实现一个hash函数:

hashcode("abcd") = (ascii(a) * 333 + ascii(b) * 332ascii(c) *33 + ascii(d)) % HASH_SIZE 

                              = (97* 333 + 98 * 332 + 99 * 33 +100) % HASH_SIZE

                              = 3595978 % HASH_SIZE

For key="abcd" and size=100, return 78

这道题主要考察对数字溢出的处理,只有把res声明为long长整型,并且在中途不断取模,才能不溢出。

    public int hashCode(char[] key,int HASH_SIZE) {
        long ans = 0;
        for (int i = 0; i < key.length; i++) {
            ans = (ans * 33 + (int)(key[i])) % HASH_SIZE;
        }
        return (int)ans;
    }

129. Rehashing

要求做一个hash,size是原来的两倍。就不断遍历原来的hash数组,如果那个位置上存在元素,则计算那个元素的新index下标,并加入到新的hash数组中去。记得处理一个下标下存的多个元素。


545. Top k Largest Numbers II

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值