5th Feb: 刷题笔记

387. First Unique Character in a String


Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1.


Examples:


s = "leetcode"
return 0.


s = "loveleetcode",
return 2.
Note: You may assume the string contain only lowercase letters.


自己想的方法:利用一个hashtable记录已经遇到的char,接着如果重复出现的话,把value置成-1。然后找values()里面除了-1最小的值就好了。


做这道题的时候,遇到的困难是values()返回的是一个Collection。这个Collection的作用是,只能使用exhanced for去遍历,却不能转换成List或者其它子类。所以,不能使用Collections.sort去做。


public class Solution {
    public int firstUniqChar(String s) {
        if (s == null) {
            return -1;
        } 
        
        if (s.length() == 1) {
            return 0;
        }
        
        //use the hashtable to record
        HashMap<Character, Integer> wordIndex = new HashMap<Character, Integer>();
        
        for (int i = 0; i < s.length(); i++) {
            if (wordIndex.containsKey(s.charAt(i))) {
                wordIndex.put(s.charAt(i), -1);
            } else {
                wordIndex.put(s.charAt(i), i);
            }
        }
        
        int min = Integer.MAX_VALUE;
        
        for (Integer tmp : wordIndex.values()) {
            if (tmp != -1) {
                min = tmp < min ? tmp : min;
            }
        }
        
        if (min == Integer.MAX_VALUE) {
            return -1;
        }
        
        return min;
    }
}

然而,比较简单的做法有两个:第一个方法,利用字典HashTable的做法,字母和出现次数对。再遍历一次链表,找出最先只出现一次的字母;第二个方法,利用String类提供的firstIndex和lastIndex的方法。如果一个字母有重复的话,两个函数的返回值肯定不一样。找到返回相同值的最小值即可。


第一个方法代码 (明天写):




第二个方法代码(明天写):


155. Min Stack


Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.


push(x) -- Push element x onto stack.
pop() -- Removes the element on top of the stack.
top() -- Get the top element.
getMin() -- Retrieve the minimum element in the stack.
Example:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> Returns -3.
minStack.pop();
minStack.top();      --> Returns 0.
minStack.getMin();   --> Returns -2.


这题做错的地方:对于getMin函数不能使用sort,直接使用Collections.min即可。由于Java已经弃用了Stack,所以这道题用LinkedList实现即可。但是使用LinkedList实现Stack需要注意,使用addFirst和removeFirst比Last要好。因为自己实现链表的时候也知道,当addLast和removeLast的话,需要遍历整个链表,十分低效且无谓。


代码如下:


public class MinStack {
    private LinkedList<Integer> storage;
    
    /** initialize your data structure here. */
    public MinStack() {
        this.storage = new LinkedList<Integer>();
    }
    
    public void push(int x) {
        storage.addFirst(x);
    }
    
    public void pop() {
        storage.removeFirst();
    }
    
    public int top() {
        int ans = storage.peekFirst();
        return ans;
    }
    
    public int getMin() {
        return Collections.min(storage);
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */


42. Trapping Rain Water


Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining.


For example, 
Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6.

这题一开始的思考方向错了,后来看了烙印网站的视频,其实很好理解。首先,某个towel (bar)所能储存的水量其实是当前水桶的“短板” - 当前bar的高度决定的。但是,并不是所有的bar都能储水。所以我们首先需要判断这个bar能不能储水。如果能储水,就把水量加到要返回的水量总和当中。


怎么判断当前bar能不能储水呢?


这就是比较tricky的地方了。主要看这个bar的左边的所有bar中最高的bar是否能高过这个bar且右边的所有bar中最高的bar是否能高过这个bar。如果两边都满足,这个bar能储水。否则,直接跳过这个bar即可。


public class Solution {
    public int trap(int[] height) {
        if (height == null || height.length < 3) {
            return 0;
        }
        
        int[] maxHeightLeft = new int[height.length];
        int[] maxHeightRight = new int[height.length];
        
        maxHeightLeft[0] = 0;
        maxHeightRight[height.length - 1] = 0;
        
        int maxHeight = 0;
        //fill in those two arrays
        for (int i = 1; i < height.length; i++) {
            maxHeight = 0;
            for (int j = i - 1; j > -1; j--) {
                maxHeight = height[j] > maxHeight ? height[j] : maxHeight;
            }
            maxHeightLeft[i] = maxHeight;
        }
        
        for (int i = 0; i < height.length - 1; i++) {
            maxHeight = 0;
            for (int j = i + 1; j < height.length; j++) {
                maxHeight = height[j] > maxHeight ? height[j] : maxHeight;
            }
            maxHeightRight[i] = maxHeight;
        }
        
        //simple logic
        int trap = 0;
        
        for (int index = 0; index < height.length; index++) {
            if (height[index] > maxHeightLeft[index] || height[index] > maxHeightRight[index]) {
                continue;
            }
            
            trap += (Math.min(maxHeightLeft[index], maxHeightRight[index]) - height[index]);
        }
        
        return trap;
    }
}

116. Populating Next Right Pointers in Each Node



Given a binary tree


    struct TreeLinkNode {
      TreeLinkNode *left;
      TreeLinkNode *right;
      TreeLinkNode *next;
    }
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.


Initially, all next pointers are set to NULL.


Note:


You may only use constant extra space.
You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).
For example,
Given the following perfect binary tree,
         1
       /  \
      2    3
     / \  / \
    4  5  6  7
After calling your function, the tree should look like:
         1 -> NULL
       /  \
      2 -> 3 -> NULL
     / \  / \
    4->5->6->7 -> NULL


117. Populating Next Right Pointers in Each Node II


Follow up for problem "Populating Next Right Pointers in Each Node".


What if the given tree could be any binary tree? Would your previous solution still work?


Note:


You may only use constant extra space.
For example,
Given the following binary tree,
         1
       /  \
      2    3
     / \    \
    4   5    7
After calling your function, the tree should look like:
         1 -> NULL
       /  \
      2 -> 3 -> NULL
     / \    \
    4-> 5 -> 7 -> NULL


这两题之所以结合在一起讲,是因为直接用117的代码就可以通过116的题目。116只是117的特殊形式(完全二叉树)。


看完了烙印网站 I Deserve 的视频后,这题的思路只需要记住下面的递归过程即可:


Step 1: 当前节点是叶子节点或者为null的时候返回(base case);

Step 2:链接当前节点的左右两个孩子(如果有两个孩子的话,因为step1,确保了至少有一个孩子):左孩子.right = 右孩子。并且把孩子与其它的同层次的孩子的right都链接了。当时这里需要这样判断逻辑:


if (有两个孩子) {

链接两个孩子,链接右孩子和root.right的左孩子或者右孩子(如果有的话)。这里自己写的时候漏了考虑:如果root的right没有孩子,当时root.right.right有呢?所以这里需要另外设置个neighbour变量,然后用while直到找到当前的左/右孩子的右边的节点为止或者遍历完所有root的neighbour。

} else {

用那个唯一的孩子,直接连接到root的neighbour的孩子(如果有)。与上述黑体字过程一致。

}


Step 3:递归调用右孩子;

Step 4:递归调用左孩子;


为什么要优先调用右孩子呢?就是为了确保上述黑体字的过程能顺利实现。否则,可能不能找完所有的neighbours. 


代码如下:


public class Solution {
    public void connect(TreeLinkNode root) {
        if (root == null || (root.left == null && root.right == null)) {
            return;
        }
        
        if (root.left != null && root.right != null) {
            root.left.next = root.right;
            TreeLinkNode parentNeibour = root.next;
            while (parentNeibour != null) {
                if (parentNeibour.left != null || parentNeibour.right != null) {
                    root.right.next = (parentNeibour.left == null ? parentNeibour.right : parentNeibour.left);
                    break;
                }
                parentNeibour = parentNeibour.next;
            }
        } else {
            TreeLinkNode child = (root.left != null ? root.left : root.right);
            TreeLinkNode parentNeibour = root.next;
            while (parentNeibour != null) {
                if (parentNeibour.left != null || parentNeibour.right != null) {
                    child.next = (parentNeibour.left == null ? parentNeibour.right : parentNeibour.left);
                    break;
                }
                parentNeibour = parentNeibour.next;
            }
        }
        
        connect(root.right);
        connect(root.left);
    }
}

160. Intersection of Two Linked Lists


Write a program to find the node at which the intersection of two singly linked lists begins.




For example, the following two linked lists:


A:          a1 → a2
                   ↘
                     c1 → c2 → c3
                   ↗            
B:     b1 → b2 → b3
begin to intersect at node c1.




Notes:


If the two linked lists have no intersection at all, return null.
The linked lists must retain their original structure after the function returns.
You may assume there are no cycles anywhere in the entire linked structure.
Your code should preferably run in O(n) time and use only O(1) memory.


这道题其实很tricky,做这道题之前,需要知道cycleLinkedList的判断标准:快慢指针能否相遇。


且如何找到circle的起点:slow.next = head的时候,head就是起点,否则一直:head = head.next; slow = slow.next;


这些在http://blog.csdn.net/firehotest/article/details/52665467 提到过,知道了这些之后,这道题就可以很tricky地解决了。把headB放到headA之后,然后看看有没有cycle。如果有就是有交叉点啦。然后通过slow.next = head的方法找到交叉点。接着返回交叉点即可。


代码:


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    private ListNode cycleLinkedListII(ListNode head) {
        if (head == null || head.next == null) {
            return null;
        }
        
        ListNode fast = head.next;
        ListNode slow = head;
        
        while (fast != slow) {
            if (fast == null || fast.next == null) {
                return null;
            }
            fast = fast.next.next;
            slow = slow.next;
        }
        
        while (head != slow.next) {
            head = head.next;
            slow = slow.next;
        }
        
        return head;
    }
    
    
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) {
            return null;
        }
        
        ListNode cur = headA;
        
        while (cur.next != null) {
            cur = cur.next;
        }
        
        cur.next = headB;
        
        ListNode result = cycleLinkedListII(headA);
        
        cur.next = null;
        
        return result;
        
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算机试库系统,是将编好的试、答案、编码事先存入计算机的外部存储器(硬盘、光盘等),使用时,通过软件的控制,按照一定的方式和规则,将试抽取、组合,形成试卷,打印输出。 使用计算机试库系统可以大大提高工作效率,不论是抽、组卷,还是提取答案、打印试卷,都非常迅速。同时,用计算机随机抽取试,可以排除人为因素和误差,使试的范围、难度、型标准一致,试卷规范,保证教育测量的客观、公正。 本试库系统由两部分组成:一是试库本身(试、答案、编码),二是试库管理软件。试库是系统的基础、原材料,软件是系统的调度者、加工者。 一、主要特点 1.直接利用Office平台 可以使用Word、Excel的所有功能,特别是它的编辑、排版、打印功能。 由于Word、Excel是人们最为熟悉、用户最为广泛的软件平台,用其内嵌的编程语言VBA进行二次开发得到的应用软件,既可以使大量繁琐、重复操作的自动化,提高工作效率和应用水平,同时又不改变原有的界面风格、系统功能和操作方式。人们不必花时间去适应另外一种软件环境,学习另外一种操作方式,大大降低使用门槛,提高了软件的可用性。 2.拷贝即用,绿色软件 本试库管理系统包含一个Word文档和一个Excel工作簿文件(均带有VBA程序),只要将这两个文件拷贝到任何装有Office 2002以上版本系统的计算机中就可以直接使用,不用时可直接删除。不像一般软件那样包含大量系统文件,要进行安装和卸载。 3.可以管理多媒体试库 由于试、答案、试卷、参数全部在Word文档中,所以可以方便地处理文字、图形、表格、公式、符号,甚至声音、视频等信息,管理多媒体试库。 4.在理论和技术上具有先进性 利用教育测量理论的最新研究成果,合理设置试参数,动态制定组卷策略,使库科学、合理。同时,采用先进的软件技术和算法,提高了时空效率,增加了通用性、可维护性和可移植性。 二、基本功能 1.库维护 本软件作为一个通用试库管理系统,可以管理各种试库。每一门课程的试库为一个Word文档,其中包括若干道试以及其答案。对每一道试的参数、干和答案,可直接在Word环境中进行增、删、改、排等操作。可随时检测是否有重复。为醒目起见,系统可自动将试和答案的参数涂上不同颜色。可对试和答案的参数进行有效性检验。 2.信息统计 统计整个库中各章、各型、各难度的试数量、分数,总量,总分数。指定组卷时各章、各型、各难度的试的抽取数量后,系统可统计出抽取的总数,总分数。 3.生成试卷 按照预先设置或临时制定的组卷策略,即各章、各型、各难度的抽数量,进行随机或排他抽,组成试卷和答案文档。 4.试卷加工 可以用Word本身的功能对试卷进行编辑、排版、打印等操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值