zoukankan      html  css  js  c++  java
  • 数据结构题目总结

    数据结构题目专题

      数据结构的题目都比较死,套路比较单一,只要各个数据结构都熟悉它们的操作,就可以上手去干题目了。

      大概分为三种类型:顺序表类型、树类型、图类型。

      细分为:数组、链表、栈、队列、二叉树、无向图、有向图等。

    2. Add Two Numbers

      

       比如这题,使用链表来表示一个整数,将两个数加起来然后返回一个链表,据说今日某条的笔试题有这道题。看着submit好像是三年前的,代码写得太丑了,抽空重写下再贴吧。

       思路就是把他俩反转,挨个加了之后返回一个链表。

    19. Remove Nth Node From End of List

      

       要求去掉从末尾往前数n位的节点,好几种思路。比如可以把链表反转,顺序去掉,或者统计长度,对n取补,去掉算出来的位置就好。这题有坑,去掉第一个节点时候掉坑里了。

        public ListNode removeNthFromEnd(ListNode head, int n) {
            if(head == null){
                return null;
            }
            int len = 0 ;
            ListNode tmp = head;
            while (tmp != null){
                len ++;
                tmp = tmp.next;
            }
    
            int fromHead = len - n;
            if(fromHead < 1){
                head = head.next;
            }else {
                ListNode skip = head;
                for(int i=1;i<fromHead;i++){
                    if(skip != null)
                        skip = skip.next;
                }
                if(skip != null){
                    ListNode skipNext = skip.next;
                    if(skipNext != null){
                        skip.next = skipNext.next;
                    }
                }
            }
            return head;
        }

    24. Swap Nodes in Pairs

      

       链表每两个节点反转,先做这题就会做k group了,自从用了LC,就喜欢上了绿色。

    class Solution {
        public ListNode swapPairs(ListNode head) {
            if(head == null){
                return null;
            }
            ListNode pre = new ListNode(-1);
            pre.next = head;
            ListNode change1 = null;
            ListNode change2 = null;
            int control = 0;
            ListNode runner = head;
            while(runner != null){
                if(control == 0){
                    change1 = runner;
                    control ++;
                    runner = runner.next;
                }else if(control == 1){
                    change2 = runner;
                    runner = runner.next;
                    if(pre.next == head){
                        head = change2;
                    }
                    pre.next = change2;
                    change1.next = change2.next;
                    change2.next = change1;
    
                    pre = change1;
    
                    control --;
                }
            }
            return head;
        }
    }

    25. Reverse Nodes in k-Group

      

       这个题的题意就是一个链表可以根据k分成它的等差区间:(0,k-1),(k,2k-1).....

       把这些按区间反转,没有想到优化方案。

    class Solution {
        public ListNode reverseKGroup(ListNode head, int k) {
            if(head == null){
                return null;
            }
            if(k == 0){
                return head;
            }
            int control = 1;
            ListNode pre1 = new ListNode(-1);
            pre1.next = head;
            ListNode change1 = null;
            ListNode change2 = null;
    
            ListNode runner = head;
            while(runner != null){
                if(control == 1){
                    change1 = runner;
                }else if(control == k){
                    change2 = runner;
                    runner = runner.next;
                    if(pre1.next == head){
                        head = change2;
                    }
                    ListNode temp = change1;
                    ListNode revertHead = null;
                    while(temp != runner){
                        ListNode cur = temp;
                        temp = temp.next;
                        if(revertHead == null) {
                            cur.next = runner;
                        }else {
                            cur.next = revertHead;
                        }
                        revertHead = cur;
                    }
                    pre1.next = revertHead;
    
                    pre1 = change1;
                    control = 1;
                    continue;
                }
    
                control ++;
                runner = runner.next;
            }
            return head;
        }
    
    }

    43. Multiply Strings

      

       大整数乘法,别看这玩意的案例才5万多,坑多得很,使用数组模拟列竖式计算,每个数组位只记十位数的一位。

    class Solution {
        public String multiply(String num1, String num2) {
            if(num1 == null || num2 ==null || num1.isEmpty() || num2.isEmpty()
                || "0".equals(num1) || "0".equals(num2)){
                return "0";
            }
            int[] resultArray = new int[1000];
            Arrays.fill(resultArray,-1);
            int baseCode = 48;
            int bit = 0;
            for(int i=num2.length()-1;i>=0;i--){
                int j=num1.length()-1;
                int currentBitBase = num2.charAt(i) - baseCode;
                int eachK = bit;
                while(j>=0){
                    int curResult = (num1.charAt(j) - baseCode)*currentBitBase ;
                    if(resultArray[eachK] < 0){
                        resultArray[eachK] = curResult ;
                    }else {
                        resultArray[eachK] += curResult;
                    }
                    eachK ++;
                    j--;
                }
                bit ++;
            }
            int lastIndex ;
            int carry = 0;
            for(lastIndex = 0;lastIndex<resultArray.length;lastIndex++){
                if(resultArray[lastIndex] < 0)
                    break;
                else {
                    resultArray[lastIndex] += carry;
                    carry = 0;
                    if(resultArray[lastIndex] >= 10){
                        carry = resultArray[lastIndex]/10;
                        resultArray[lastIndex] %= 10;
                    }
                }
            }
            if(carry > 0){
                resultArray[lastIndex] = carry;
            }else {
                lastIndex--;
            }
    
            StringBuilder intValue = new StringBuilder();
            for(;lastIndex>=0;lastIndex--){
                intValue.append(resultArray[lastIndex]);
            }
    
            return intValue.toString();
        }
    }

    49. Group Anagrams

      

        按字母分类,使用哈希表。

        每次把拿到的字符按字典序排序一下,作为key。

    class Solution {
        public List<List<String>> groupAnagrams(String[] strs) {
            if (strs.length == 0) return new ArrayList();
            Map<String, List<String>> ans = new HashMap<>();
            for (String s : strs) {
                char[] carr = s.toCharArray();
                Arrays.sort(carr);
                StringBuilder sb = new StringBuilder();
                for(char c : carr){
                    sb.append(c);
                }
                if(!ans.containsKey(sb.toString())){
                    ans.put(sb.toString(),new ArrayList<String>());
                }
                ans.get(sb.toString()).add(s);
            }
            return new ArrayList(ans.values());
        }
    }

    23. Merge k Sorted Lists

      

       将一个链表数组,合成一个链表。使用优先队列,把所有节点全扔进去,然后再拿出来。

    class Solution {
        public ListNode mergeKLists(ListNode[] lists) {
            PriorityQueue<Integer> queue = new PriorityQueue();
            for(ListNode h : lists){
                ListNode temp = h;
                while(temp != null){
                    queue.add(temp.val);
                    temp = temp.next;
                }
            }
            ListNode head = null;
            ListNode tail = null;
            while(!queue.isEmpty()){
                if(head == null){
                    head = new ListNode(queue.poll());
                    tail = head;
                }else {
                    tail.next = new ListNode(queue.poll());
                    tail = tail.next;
                }
            }
            return head;
        }
    }

    57. Insert Interval

      

       区间插入,虽然是hard但是略水,没beat 100,提高了10倍也还是20%的水平,无爱了。

    class Solution {
        /**
         * 区间插入
         *
         */
        public int[][] insert(int[][] intervals, int[] newInterval) {
            List<int[]> orgin = new ArrayList<>(Arrays.asList(intervals));
            boolean append = false;
            for(int i=0;i<orgin.size();i++){
                if(newInterval[0]<=orgin.get(i)[0]){
                    orgin.add(i,newInterval);
                    append = true;
                    break;
                }
            }
            if(!append)
                orgin.add(newInterval);
    
            int[][] newIntervals = orgin.toArray(new int[orgin.size()][]);
    
            List<int[]> mergeList = new ArrayList<>(newIntervals.length);
            for (int[] newInterval1 : newIntervals) {
                if (mergeList.size() > 0) {
                    int[] last = mergeList.get(mergeList.size() - 1);
                    if (last[1] >= newInterval1[0]) {
                        last[1] = Math.max(last[1], newInterval1[1]);
                        mergeList.set(mergeList.size() - 1, last);
                    } else {
                        mergeList.add(newInterval1);
                    }
                } else {
                    mergeList.add(newInterval1);
                }
            }
    
            return mergeList.toArray(new int[mergeList.size()][]);
        }
    }

    61. Rotate List  

      

      题意是链表像一个环一样,每个位置向右滚动k个位置。思路就是将它弄成环,然后找到新的head,再断开。

    class Solution {
        public ListNode rotateRight(ListNode head, int k) {
            if(head == null || k == 0){
                return head;
            }
            int len = 1;
            ListNode runner = head;
            while(runner.next != null){
                len ++;
                runner = runner.next;
            }
            runner.next = head;
    
            int runTimes = len - (k % len);
    
            ListNode pre = head;
            ListNode newHead = head.next;
    
            for(int i=1;i<runTimes;i++){
                pre = pre.next;
                newHead = newHead.next;
            }
            pre.next = null;
    
            return newHead;
        }
    }

    86. Partition List

       

       被快排的partition荼毒了,它的要求是将大于等于x的划分成一个链表,小于x的分成另一个链表,然后再进行拼接。注意,这里的链表顺序是不能变的。

      比如小于3的,就是1,2,2;大于等于3的是4,3,5;然后他们合起来是1,2,2,4,3,5。

    class Solution {
        public ListNode partition(ListNode head, int x) {
          if(head == null)
                return head;
            ListNode smallHead = null;
            ListNode small = null;
            ListNode big = null;
            ListNode bigHead = null;
            while (head != null){
                ListNode current = head;
                head = head.next;
                if(current.val < x){
                    if(small == null){
                        small = current;
                        smallHead = small;
                    }else {
                        small.next = current;
                        small = small.next;
                    }
                    small.next = bigHead;
                }else {
                    if(big == null){
                        big = current;
                        bigHead = big;
                    }else {
                        big.next = current;
                        big = big.next;
                    }
                    big.next = null;
                }
    
            }
            if(small != null){
                small.next = bigHead;
            }
            return smallHead == null ? bigHead : smallHead;
        }
    }

    80. Remove Duplicates from Sorted Array II

      

       这题是给定一个数组,去掉它的duplicate值,然后返回长度,它的长度是原数组从头开始算的长度,所有的操作都在原数组上执行。

       竟然还有人比我快,O(n)的系数比我小么。

    class Solution {
        public int removeDuplicates(int[] nums) {
            if(nums.length < 3){
                return nums.length;
            }
            int len = 0;
            int duplicates = 0;
            int currentVal = nums[0];
            for(int i=0;i<nums.length;i++){
                if(nums[i] == currentVal && duplicates < 2){
                    duplicates ++;
                    nums[len++] = nums[i];
                }else if(nums[i] == currentVal){
                    continue;
                }else if(nums[i] != currentVal){
                    currentVal = nums[i];
                    duplicates = 1;
                    nums[len++] = nums[i];
                }
            }
            return len; 
        }
    }

    102. Binary Tree Level Order Traversal

      

       二叉树层序遍历。

    class Solution {
        public List<List<Integer>> levelOrder(TreeNode root) {
            List<List<Integer>> result = new ArrayList<>();
            if(root == null){
                return result;
            }
    
            Queue<TreeNode> currentLevel = new ArrayDeque<>();
            currentLevel.add(root);
            Queue<TreeNode> nextLevel = new ArrayDeque<>();
    
            List<Integer> levelResult = new ArrayList<>();
            while (!currentLevel.isEmpty()){
                TreeNode node = currentLevel.poll();
                levelResult.add(node.val);
                if(node.left != null){
                    nextLevel.add(node.left);
                }
                if(node.right != null){
                    nextLevel.add(node.right);
                }
                if(currentLevel.isEmpty()){
                    result.add(new ArrayList<>(levelResult));
                    levelResult.clear();
                    currentLevel = nextLevel;
                    nextLevel = new ArrayDeque<>();
                }
            }
            return result;
        }
    }

    103. Binary Tree Zigzag Level Order Traversal

      

       二叉树z字型遍历,花式。

    class Solution {
        public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
                    List<List<Integer>> result = new ArrayList<>();
            if(root == null){
                return result;
            }
    
            Stack<TreeNode> currentStack = new Stack<>();
            Stack<TreeNode> nextStack = new Stack<>();
    
            currentStack.push(root);
            List<Integer> levelResult = new ArrayList<>();
            while (!currentStack.isEmpty()){
                TreeNode node = currentStack.pop();
                levelResult.add(node.val);
                if(result.size() % 2 == 0){
                    if(node.left != null){
                        nextStack.push(node.left);
                    }
                    if(node.right != null){
                        nextStack.push(node.right);
                    }
                }else {
                    if(node.right != null){
                        nextStack.push(node.right);
                    }
                    if(node.left != null){
                        nextStack.push(node.left);
                    }
    
                }
                if(currentStack.isEmpty()){
                    result.add(new ArrayList<>(levelResult));
                    levelResult.clear();
                    currentStack = nextStack;
                    nextStack = new Stack<>();
                }
            }
            return result;
        }
    }

    144. Binary Tree Preorder Traversal

      

       二叉树前序遍历,也就是根->左->右。学到了俩单词,Preorder,Traversal。

       最后还问你,能整成循环么?当然不能,天天加料加需求。

    class Solution {
        public List<Integer> preorderTraversal(TreeNode root) {
            List<Integer> result = new ArrayList<>();
            if(root == null){
                return result;
            }
            preorder(root,result);
            return result;
        }
        void preorder(TreeNode node,List<Integer> result){
            if(node == null){
                return;
            }
            result.add(node.val);
            preorder(node.left,result);
            preorder(node.right,result);
        }
    }
        void preorderIteratively(TreeNode node,List<Integer> result){
    
            Stack<TreeNode> stack = new Stack<>();
            stack.push(node);
    
            while (!stack.isEmpty()) {
                TreeNode cur = stack.pop();
                if (cur.right != null) {
                    stack.push(cur.right);
                }
                if (cur.left != null) {
                    stack.push(cur.left);
                }
                result.add(cur.val);
            }
        }

    145. Binary Tree Postorder Traversal

      

       水题,白给hard。后序遍历,不过循环做还是难的。

    class Solution {
        public List<Integer> postorderTraversal(TreeNode root) {
            List<Integer> result = new ArrayList<>();
            if(root == null)
                return result;
            postorderIteratively(root,result);
            return result;
        }
        /**
         * post order means left->right->root
         *
         */
        void postorderIteratively(TreeNode node,List<Integer> result){
            Stack<TreeNode> stack = new Stack<>();
            TreeNode curr = node;
            while(!stack.isEmpty() || curr != null){
                if(curr != null){
                    stack.push(curr);
                    result.add(0, curr.val);
                    curr = curr.right;
                }else{
                    TreeNode top = stack.pop();
                    curr = top.left;
                }
            }
        }
    }

    94. Binary Tree Inorder Traversal

      

       中序遍历。

    class Solution {
        public List<Integer> inorderTraversal(TreeNode root) {
            List<Integer> result = new ArrayList<>();
            Stack<TreeNode> stack = new Stack<>();
            TreeNode cur = root;
            while(!stack.isEmpty() || cur != null){
                if(cur != null){
                    stack.push(cur);
                    cur = cur.left;
                }else {
                    TreeNode n = stack.pop();
                    result.add(n.val);
                    cur = n.right;
                }
            }
    
            return result;
        }
    }

    133. Clone Graph

       

       克隆一个无向图,实际上就是遍历,图的定义就是这么简洁。遍历图一定要有visitd标识。

       深度优先,就是使用栈。每次将未访问的邻居节点加入stack。

       广度优先,使用队列。

    class Node {
        public int val;
        public List<Node> neighbors;
    
        public Node() {}
    
        public Node(int _val,List<Node> _neighbors) {
            val = _val;
            neighbors = _neighbors;
        }
    };
    class Solution {
        /**
         * 克隆一个图
         */
        public Node cloneGraph(Node node) {
            return dfs(node);
        }
    
        /**
         * 深度优先拷贝
         */
        Node dfs(Node node){
            if(node == null){
                return null;
            }
            Stack<Node> stack = new Stack<>();
            Set<Node> visited = new HashSet<>();
            Map<Integer,Node> newGraph = new HashMap<>();
            newGraph.put(node.val,cloneGraphNode(node));
            visited.add(node);
            stack.push(node);
            while (!stack.isEmpty()){
                Node cur = stack.pop();
                Node newNode = newGraph.get(cur.val);
                if(newNode == null){
                    newNode = cloneGraphNode(cur);
                    newGraph.put(newNode.val,newNode);
                }
                for(Node n : cur.neighbors){
                    if(!visited.contains(n)){
                        stack.push(n);
                        visited.add(n);
                    }
                    Node nn = newGraph.get(n.val);
                    if(nn == null){
                        nn = cloneGraphNode(n);
                        newGraph.put(nn.val,nn);
                    }
                    newNode.neighbors.add(nn);
                }
    
            }
            return newGraph.get(node.val);
        }
        Node cloneGraphNode(Node n){
            if(n == null){
                return null;
            }
            return new Node(n.val,new ArrayList<>());
        }
    }
    class Solution {
        /**
         * 克隆一个图
         */
        public Node cloneGraph(Node node) {
            return bfs(node);
        }
    
        /**
         * 广度优先拷贝
         */
        Node bfs(Node node){
            if(node == null){
                return null;
            }
            Queue<Node> queue = new ArrayDeque<>();
            Set<Node> visited = new HashSet<>();
            Map<Integer,Node> newGraph = new HashMap<>();
            queue.add(node);
            while (!queue.isEmpty()){
                Node cur = queue.poll();
                if(visited.contains(cur))
                    continue;
                Node newNode = null;
                if((newNode = newGraph.get(cur.val)) == null){
                    newGraph.put(cur.val,newNode=cloneGraphNode(cur));
                }
                for(Node n :cur.neighbors){
                    Node nn = newGraph.get(n.val);
                    if(nn == null){
                        newGraph.put(n.val,nn = cloneGraphNode(n));
                    }
                    newNode.neighbors.add(nn);
                    if(!visited.contains(n)){
                        queue.add(n);
                    }
                }
                visited.add(cur);
            }
            return newGraph.get(node.val);
        }
        Node cloneGraphNode(Node n){
            if(n == null){
                return null;
            }
            return new Node(n.val,new ArrayList<>());
        }
    }

    树状数组(Binary Indexed Tree)

      这是一种非常巧妙的数据结构,是为了解决前缀和n次询问的产生的。

      有一个数组n,它是一个离散的列,要求他的前i项和怎么办。

      第一种解法,就是for循环,从0加到i,这样的复杂度是O(n)。

      第二种解法,使用一个额外的数组,去保存前n项和。这样,询问的复杂度是O(1),但是更新的复杂度是O(n)。

      有一种解法,是树状数组。它的询问和更新都能到达O(logn)

       它的原理和证明,我不是很能理解,但是它这种数据结构是用来计算前n项和的n次询问的,这样的复杂度能到达O(logn),并且在支持动态更新的时候非常良好。

       实现这种数据结构很简单,只需要三个方法。lowbit方法,是计算下一个值所在位置;update是更新数组,getSum 或者 平时叫的 query 是查询前n项和。

     int lowbit(int x){
            return x & (-x);
        }
        void update(int[] array,int x,int k){
            int i = x + 1;
            while(i<array.length){
                array[i] += k;
                i += lowbit(i);
            }
        }
        int getSum(int[] array,int x){
            int res = 0;
            int i = x + 1;
            while (i>0){
                res += array[i];
                i -= lowbit(i);
            }
            return res;
        }

       这道题,使用前n项和去解。

    public class ReversePairs {
        public void test(){
            int[] nums1 = {1,3,2,3,1};
            // 2
            System.out.println(reversePairs(nums1));
            int[] nums2 = {2,4,3,5,1};
            // 3
            System.out.println(reversePairs(nums2));
            int[] nums3 = {5,4,3,2,1,2,1};
            // 8
            System.out.println(reversePairs(nums3));
            // 0
            int[] nums4 = {2147483647,2147483647,2147483647,2147483647,2147483647,2147483647};
            System.out.println(reversePairs(nums4));
        }
    
        /**
         * binary indexed tree
         * build a BIT count nums[i]/2
         * rule : i<j ,nums[i] > 2*nums[j]
         */
        public int reversePairs(int[] nums) {
            int res = 0;
            int n = nums.length;
            // for binary search
            long[] copy = new long[n];
            for(int i=0;i<nums.length;i++){
                copy[i] = nums[i];
            }
            Arrays.sort(copy);
            int[] BIT = new int[n+1];
            for (int i = 0; i < n; ++i) {
                // for current i
                // we count 2*nums[i]+1 for each nums[i]
                res += getSum(BIT,copy.length - 1) - getSum(BIT,binarySearch(copy, 2 * (long)nums[i] + 1) - 1);
                update(BIT,binarySearch(copy, (long)nums[i]),1);
            }
            return res;
        }
        int lowbit(int x){
            return x & (-x);
        }
        void update(int[] array,int x,int k){
            int i = x + 1;
            while(i<array.length){
                array[i] += k;
                i += lowbit(i);
            }
        }
        int getSum(int[] array,int x){
            int res = 0;
            int i = x + 1;
            while (i>0){
                res += array[i];
                i -= lowbit(i);
            }
            return res;
        }
        int binarySearch(long[] sortArray,long value){
            int n = sortArray.length;
            int l = 0;
            int r = n - 1;
            while (l + 1 < r) {
                int m = l + (r - l) / 2;
                if (sortArray[m] >= value) {
                    r = m;
                } else {
                    l = m;
                }
            }
            if (sortArray[l] >= value) {
                return l;
            } else if (sortArray[r] >= value) {
                return r;
            } else {
                return r + 1;
            }
        }
    }
  • 相关阅读:
    SQL的高级属性-
    查询
    SQL语句
    CSS的创建样式
    表单部分属性值
    HTML的语法和基本标签
    网页制作与HTML基本结构
    小程序button 去边框
    关于axios跨域带cookie
    Uncaught Error: code length overflow. (1604>1056)
  • 原文地址:https://www.cnblogs.com/chentingk/p/11655834.html
Copyright © 2011-2022 走看看