• 《剑指offer》算法题第十天


    今日题目:

    1. 数组中的逆序对
    2. 两个链表的第一个公共节点
    3. 数字在排序数组中出现的次数
    4. 二叉搜索树的第k大节点
    5. 字符流中第一个不重复的字符

    1. 数组中的逆序对

    题目描述:
    在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。

    思路:
    这道题运用归并排序的思想来求解,归并排序是面试中经常问到的知识点,得经常翻出来熟悉熟悉。

    代码如下:

     1 public class Solution {
     2     int cnt;
     3  
     4     public int InversePairs(int[] array) {
     5         cnt = 0;
     6         if (array != null)
     7             mergeSortUp2Down(array, 0, array.length - 1);
     8         return cnt;
     9     }
    10  
    11     /*
    12      * 归并排序(从上往下)
    13      */
    14     public void mergeSortUp2Down(int[] a, int start, int end) {
    15         if (start >= end)
    16             return;
    17         int mid = (start + end) >> 1;
    18  
    19         mergeSortUp2Down(a, start, mid);
    20         mergeSortUp2Down(a, mid + 1, end);
    21  
    22         merge(a, start, mid, end);
    23     }
    24  
    25     /*
    26      * 将一个数组中的两个相邻有序区间合并成一个
    27      */
    28     public void merge(int[] a, int start, int mid, int end) {
    29         int[] tmp = new int[end - start + 1];
    30  
    31         int i = start, j = mid + 1, k = 0;
    32         while (i <= mid && j <= end) {
    33             if (a[i] <= a[j])
    34                 tmp[k++] = a[i++];
    35             else {
    36                 tmp[k++] = a[j++];
    37                 cnt += mid - i + 1;  // core code, calculate InversePairs............
    38                 cnt %= 1000000007;
    39             }
    40         }
    41  
    42         while (i <= mid)
    43             tmp[k++] = a[i++];
    44         while (j <= end)
    45             tmp[k++] = a[j++];
    46         for (k = 0; k < tmp.length; k++)
    47             a[start + k] = tmp[k];
    48     }
    49 }

    2.两个链表中的第一个公共节点

    题目描述:
    输入两个链表,找出它们的第一个公共结点。

    思路:
    《剑指offer》中的参考答案利用了两个栈来分别存储两个链表,然后从链尾到链头遍历两个链表,寻找公共的节点。但是博主觉得没必要那么麻烦,运用一个hashset就能够处理这道题。
    另外,在这道题的讨论区中,有一个特别精妙的方法,利用两个指针遍历数组,第一趟得到链表长度的差值,第二趟寻找公共节点,下面也会贴出来。

    代码如下:

    //利用hashset
    import java.util.HashSet;
    public class Solution {
        public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
            if(pHead1 == null || pHead2 == null) return null;
            HashSet<ListNode> set = new HashSet();
            while(pHead1 != null){
                set.add(pHead1);
                pHead1 = pHead1.next;
            }
            while(pHead2 != null){
                if(set.contains(pHead2))
                    return pHead2;
                pHead2 = pHead2.next;
            }
            return null;
        }
    }
    
    
    //两个指针的方法
    public class Solution {
        public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
            ListNode p1 = pHead1;
            ListNode p2 = pHead2;
            while(p1 != p2){
                p1 = (p1==null ? pHead2 : p1.next);
                p2 = (p2==null ? pHead1 : p2.next);
            }
            return p1;
        }
    }

    3.数字在排序数组中出现的次数

    题目描述:
    统计一个数字在排序数组中出现的次数。

    思路:
    比较直接的方法是直接遍历数组,统计目标数字出现的次数,时间复杂度为O(n)。
    比较快的方法是利用二分查找的思想,时间复杂度可达到O(logn)。

    代码如下:

     1 public class Solution {
     2     int count = 0;
     3     public int GetNumberOfK(int [] array , int k) {
     4         binSearch(array,k,0,array.length-1);
     5         return count;
     6     }
     7     
     8     public void binSearch(int[] nums,int k,int start,int end){
     9         if(start == end){
    10             if(nums[start] == k) count++;
    11             return;
    12         }else if(start < end){
    13             int mid = (start+end)/2;
    14             if(nums[mid] == k){
    15                 count++;
    16                 binSearch(nums,k,start,mid-1);
    17                 binSearch(nums,k,mid+1,end);
    18             }else if(nums[mid] < k){
    19                 binSearch(nums,k,mid+1,end);
    20             }else{
    21                 binSearch(nums,k,start,mid-1);
    22             }
    23         }
    24     }
    25 }

    4.二叉搜索树的第k大节点

    题目描述:
    给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 /  3 7 / / 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。

    思路:
    比较直接,二叉树的中序遍历。不过需要提一下的是,二叉树三种遍历顺序的递归和迭代实现方式都得非常熟悉。

    代码如下:

     1 import java.util.Stack;
     2 public class Solution {
     3     TreeNode KthNode(TreeNode pRoot, int k){
     4         if(pRoot == null || k == 0) return null;
     5         Stack<TreeNode> stack = new Stack();
     6         int count = 0;
     7         while(pRoot != null || !stack.isEmpty()){
     8             if(pRoot != null){
     9                 stack.push(pRoot);
    10                 pRoot = pRoot.left;
    11             }else{
    12                 pRoot = stack.pop();
    13                 count++;
    14                 if(count == k)
    15                     return pRoot;
    16                 pRoot = pRoot.right;
    17             }
    18         }
    19         return null;
    20     }
    21 }

    5.字符流中第一个不重复的字符

    题目描述:
    请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。

    思路:
    这道题和之前的求一个数据流中的中位数的题相似,重点是如何选择一个合适的数据结构来存储数据,是的插入和查询的效率都比较高。
    在这道题中,《剑指offer》给的参考答案是声明一个int型的数组来存储各个字符的状态。这种思想非常地重要,应多做练习来熟悉。

    代码如下:

     1 public class Solution {
     2     //Insert one char from stringstream
     3     int[] map = new int[256];
     4     int index = 1;
     5     public void Insert(char ch)
     6     {//0代表还未出现相应的字符,-1代表出现一次以上,其他数字代表什么时候出现
     7         if(map[ch] == 0)
     8             map[ch] = index;
     9         else if(map[ch] > 0)
    10             map[ch] = -1;
    11         index ++;
    12     }
    13   //return the first appearence once char in current stringstream
    14     public char FirstAppearingOnce()
    15     {
    16         int min = Integer.MAX_VALUE;
    17         int ind = -1;
    18         for(int i = 0; i < 256; i++){//找出大于0的最小值及其坐标
    19             if(map[i] > 0 && map[i] < min){
    20                 min = map[i];
    21                 ind = i;
    22             }
    23         }
    24         if(ind == -1)//不存在大于0的数,则没有字符出现一次
    25             return '#';
    26         else
    27             return (char)ind;
    28     }
    29 }
  • 相关阅读:
    SpringBoot发送邮箱验证码
    判断一个数是否为2的整数次幂
    [模板] 虚树 && bzoj2286-[Sdoi2011]消耗战
    [模板] K-D Tree
    [模板] 平衡树: Splay, 非旋Treap, 替罪羊树
    对于约数个数上界的估计
    luogu3702-[SDOI2017]序列计数
    [模板] 线性基
    [模板] 区间mex && 区间元素种数
    bzoj4367-[IOI2014]holiday假期
  • 原文地址:https://www.cnblogs.com/wezheng/p/8423879.html
Copyright © 2020-2023  润新知