zoukankan      html  css  js  c++  java
  • 二.二分法总结

    一、二分法基本功

    1、通用二分模板,二分T(n)= log2n

    伪码:异常检查;start + 1 < end ;start + (end - start) / 2 ;A[mid] ==, <, >; A[start] A[end] ? target

    start= 0, end = length - 1
    
    while (start + 1 < end) {//1、循环条件相邻就退出
    
      mid = start + (end - start) // 2、mid的取值不会越界
    
      if [mid] == target {return mid or 赋值}
    
      else if [mid] <target {start = mid}
    
      else [mid] > target{end = mid}
    
    }
    //3、端点检测
    if [start] ,[end]?= target {return start or end}
    
    return - 1
    View Code

    2、题解

    1)经典(http://www.lintcode.com/problem/classical-binary-search/):在一个排序数组中找一个数,返回该数出现的任意位置,如果不存在,返回-1

    做过3次,已ac

    public class Solution {
        /**
         * @param nums: An integer array sorted in ascending order
         * @param target: An integer
         * @return an integer
         */
        public int findPosition(int[] nums, int target) {
            // Write your code here
            if (nums == null || nums.length == 0) {
                return -1;
            }
            int start = 0;
            int end = nums.length - 1;
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (nums[mid] == target) {
                    return mid;
                } else if (nums[mid] < target) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            if (nums[start] == target) {
                return start;
            }
            if (nums[end] == target) {
                return end;
            }
            return -1;
        }
    }
    View Code

    2)第一次出现位置(http://www.lintcode.com/problem/first-position-of-target/):给定一个排序的整数数组(升序)和一个要查找的整数target,用O(logn)的时间查找到target第一次出现的下标(从0开始),如果target不存在于数组中,返回-1

    做过3次,not ac :忘记end 的检查,第4次ac

    class Solution {
        /**
         * @param nums: The integer array.
         * @param target: Target to find.
         * @return: The first position of target. Position starts from 0.
         */
        public int binarySearch(int[] nums, int target) {
            //以start做返回结果
            //1、异常检查
            if (nums == null || nums.length == 0) {
                return -1;
            }
            int start = 0;
            int end = nums.length - 1;
            //2、循环条件
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (nums[mid] == target) {
                    end = mid;
                    //找第一个,返回start
                } else if (nums[mid] < target) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            // 3、端点检查,先看start
            if (nums[start] == target) {
                return start;
            }
            if (nums[end] == target) {
                return end;
            }
            return -1;
        }
    }
    View Code

    3)最后一个位置(http://www.lintcode.com/problem/last-position-of-target/):给一个升序数组,找到target最后一次出现的位置,如果没出现过返回-1

    3遍,ac

    public class Solution {
        /**
         * @param nums: An integer array sorted in ascending order
         * @param target: An integer
         * @return an integer
         */
        public int lastPosition(int[] nums, int target) {
            // Write your code here
            if (nums == null || nums.length == 0) {
                return -1;
            }
            int start = 0;
            int end = nums.length - 1;
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (nums[mid] == target) {
                    start = mid;
                } else if (nums[mid] < target) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            //先返回end
            if (nums[end] == target) {
                return end;
            }
            if (nums[start] == target) {
                return start;
            }
            return -1;
        }
    }
    View Code

     2017-03-06,11:43:29 

    待续.....(接下来的题)

    二、二分位置

    二分位置 之 OOXX :一般会给你一个数组 让你找数组中第一个/最后一个满足某个条件的位置 OOOOOOO...OOXX….XXXXXX

    1)First Bad Version(http://www.lintcode.com/problem/first-bad-version/):代码库的版本号是从 1 到 n 的整数。某一天,有人提交了错误版本的代码,因此造成自身及之后版本的代码在单元测试中均出错。请找出第一个错误的版本号。

    4,ac

    class Solution {
        /**
         * @param n: An integers.
         * @return: An integer which is the first bad version.
         */
        public int findFirstBadVersion(int n) {
            // write your code here
            int start = 1;
            int end = n;
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (SVNRepo.isBadVersion(mid)) {
                    end = mid;
                } else {
                    start = mid;
                }
            }
            if (SVNRepo.isBadVersion(start)) {
                return start;
            }
            if (SVNRepo.isBadVersion(end)) {
                return end;
            }
            return -1;
        }
    }
    View Code

    2)在大数组中查找(http://www.lintcode.com/zh-cn/problem/search-in-a-big-sorted-array/):给一个按照升序排序的正整数数组。这个数组很大以至于你只能通过固定的接口 ArrayReader.get(k) 来访问第k个数。(或者C++里是ArrayReader->get(k)),并且你也没有办法得知这个数组有多大。找到给出的整数target第一次出现的位置。你的算法需要在O(logk)的时间复杂度内完成,k为target第一次出现的位置的下标。

    **边界倍增。让要二分的区间倍增。

    1.找到一个大于targetS的位置k,用logk
    2.在区间k内二分查找,logk

    2,not ac:根据参数reader去调用函数reader.get(k)

    第3次,not ac:忘记异常检查,当== 时判断失误,不应直接返回,而应该end = mid;

    public class Solution {
        /**
         * @param reader: An instance of ArrayReader.
         * @param target: An integer
         * @return : An integer which is the index of the target number
         */
        public int searchBigSortedArray(ArrayReader reader, int target) {
            // write your code here
            //边界倍增
            /**
             *1.找到一个大于targetS的位置k,logk
             *2.在区间k内二分查找,logk
            */
            int index = 1;
            while (reader.get(index - 1) < target) {
                index = index * 2;
            }
            int start = 0, end = index - 1;
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (reader.get(mid) == target) {
                    end = mid;
                } else if (reader.get(mid) < target) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            if (reader.get(start) == target) {
                return start;
            }
            if (reader.get(end) == target) {
                return end;
            }
            return -1;
        }
    }
    View Code

    3)寻找旋转排序数组中的最小值(http://www.lintcode.com/zh-cn/problem/find-minimum-in-rotated-sorted-array/):假设一个旋转排序的数组其起始位置是未知的(比如0 1 2 4 5 6 7 可能变成是4 5 6 7 0 1 2)。你需要找到其中最小的元素。你可以假设数组中不存在重复的元素。

    3,ac:

    public class Solution {
        /**
         * @param nums: a rotated sorted array
         * @return: the minimum number in the array
         */
        public int findMin(int[] nums) {
            // write your code here
            if (nums == null || nums.length == 0) {
                return -1;
            }
            int start = 0;
            int end = nums.length - 1;
            int target = nums[nums.length - 1];
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (nums[mid] <= target) {
                    end = mid;
                } else {
                    start = mid;
                }
            }
            if (nums[start] <= target) {
                return nums[start];
            } else {
                return nums[end];
            }
        }
    }
    View Code

    4)Search a 2D Matrix(http://www.lintcode.com/en/problem/search-a-2d-matrix/):二维数组,每行从左到右递增,从上到下递增。

    ** :数组坐标转换num = matrix[mid / col][mid % col];

    3,看,ac

    4,变量名错,方法忘记啦,不用写两遍条件

    public class Solution {
        /**
         * @param matrix, a list of lists of integers
         * @param target, an integer
         * @return a boolean, indicate whether matrix contains target
         */
        public boolean searchMatrix(int[][] matrix, int target) {
            // write your code here
            //异常检测
            if (matrix == null || matrix.length == 0) {
                return false;
            }
            if (matrix[0] == null || matrix[0].length == 0) {
                return false;
            }
            int row = matrix.length;
            int col = matrix[0].length;
            int start = 0;
            int end = row * col - 1;
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                int num = matrix[mid / col][mid % col];
                if (num == target) {
                    return true;
                } else if (num < target) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            if (matrix[start / col][start % col] == target) {
                return true;
            }
            if (matrix[end / col][end % col] == target) {
                return true;
            }
            return false;
        }
    }
    View Code

    related:  Search in a 2D Matrix II(http://www.lintcode.com/zh-cn/problem/search-a-2d-matrix-ii/):

    写出一个高效的算法来搜索m×n矩阵中的值,返回这个值出现的次数。

    这个矩阵具有以下特性:

    • 每行中的整数从左到右是排序的。
    • 每一列的整数从上到下是排序的。
    • 在每一行或每一列中没有重复的整数。

    3,ac:ac 但不太熟练啦 

    **从左下-->右上,两次异常检查

    public class Solution {
        /**
         * @param matrix: A list of lists of integers
         * @param: A number you want to search in the matrix
         * @return: An integer indicate the occurrence of target in the given matrix
         */
        public int searchMatrix(int[][] matrix, int target) {
            // 从左下直到右上
            //异常检查
            if (matrix == null || matrix.length == 0) {
                return 0;
            }
            if (matrix[0] == null || matrix[0].length == 0) {
                return 0;
            }
            int m = matrix.length;
            int n = matrix[0].length;
            int x = m - 1;
            int y = 0;
            int end = 0;
            int count = 0;
            while (x >= 0 && y < n) {
                if (matrix[x][y] < target) {
                    y++;
                } else if (matrix[x][y] > target) {
                    x--;
                } else {
                    count++;
                    y++;
                    x--;
                }
            }
            return count;
        }
    }
    View Code

    5)Search for a Range(http://www.lintcode.com/en/problem/search-for-a-range/):target存在的区间

    2,代刷,ac,忘记思路

    **先找其中一个边界,然后找另一个边界,边界之差+1即为所求。

    public class Solution {
        /** 
         *@param A : an integer sorted array
         *@param target :  an integer to be inserted
         *return : a list of length 2, [index1, index2]
         */
        public int[] searchRange(int[] A, int target) {
            // write your code here
            //先找其中一个边界,然后找另一个边界
            if (A == null || A.length == 0) {
                return new int[]{-1,-1};
            }
            //不会声明一个数组 
            int[] bound = new int[2];
            int start = 0;
            int end = A.length - 1;
            //左边界
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (A[mid] < target) {
                    start = mid;
                } else if (A[mid] > target) {
                    end = mid;
                } else {
                    end = mid;
                }
            }
            if (A[start] == target) {
                bound[0] = start;
            } else if (A[end] == target) {
                bound[0] = end;
            } else {
                bound[0] = bound[1] = -1;
            }
            //右边界
            start = 0;
            end = A.length - 1;
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (A[mid] < target) {
                    start = mid;
                } else if (A[mid] > target) {
                    end = mid;
                } else {
                    start = mid;
                }
            }
            if (A[end] == target) {
                bound[1] = end;
            } else if (A[start] == target) {
                bound[1] = start;
            } else {
                bound[0] = bound[1] = -1;
            }
            return bound;
        }   
    }
    View Code

    6)Maximum Number in Mountain Sequence • http://www.lintcode.com/en/problem/maximum-number-in-mountain-sequence/:寻找最大峰值

    3,ac,代刷,四分之一区间的错了,t2 = end - (end - t1) / 2,会越界,没加1或减

    两种方法:距离l/4的比较或相邻比较

    public class Solution {
        /**
         * @param nums a mountain sequence which increase firstly and then decrease
         * @return then mountain top
         */
        public int mountainSequence(int[] nums) {
            //Write your code here
            int start = 0;
            int end = nums.length - 1;
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (nums[mid] < nums[mid + 1]) {
                    start = mid;
                } else if (nums[mid] > nums[mid + 1]) {
                    end = mid;
                } else {
                    start = mid;
                }
            }
            if (nums[start] < nums[end]) {
                return nums[end];
            } else {
                return nums[start];
            }
            // int left = 0, right = nums.length - 1;
            // while (left + 1 < right) {
            //     int m1 = left + (right - left) / 2;
            //     int m2 = right - (right - m1) / 2;
            //     if (nums[m1] < nums[m2]) {
            //         left = m1 + 1;
            //     } else if (nums[m1] > nums[m2]) {
            //         right = m2 - 1;
            //     } else {
            //         left = m1;
            //         right = m2;
            //     }
            // }
            // return nums[left] > nums[right] ? nums[left] : nums[right];
        }
    }
    View Code

    三、二分位置

     Half half 并无法找到一个条件,形成 OOXX 的模型 但可以根据判断,保留下有解的那一半或者去掉无解的一半

    1)Find Peak Element (http://www.lintcode.com/problem/find-peak-element/):

    你给出一个整数数组(size为n),其具有以下特点:

    • 相邻位置的数字是不同的
    • A[0] < A[1] 并且 A[n - 2] > A[n - 1]

    假定P是峰值的位置则满足A[P] > A[P-1]A[P] > A[P+1],返回数组中任意一个峰值的位置。

    class Solution {
        /**
         * @param A: An integers array.
         * @return: return any of peek positions.
         */
        public int findPeak(int[] A) {
            // write your code here
            //第一个和最后一个的位置是一定不符合的。
            int start = 1;
            int end = A.length - 2;
            while (start + 1 < end) {
                int mid = (start + end ) / 2;
                if (A[mid] > A[mid - 1]) {
                    start = mid;
                } else if (A[mid] > A[mid + 1]) {
                    end = mid;
                } else {
                    end = mid;
                }
            }
            // 边界检测
            if (A[start] < A[end]) {
                return end;
            } else {
                return start;
            }
        }
    }    
    View Code

      ***两次二分,第一次由mid决定二分分成红和绿,第二次分别在红绿中分1,2和3,4,由target决定

    public class Solution {
        /** 
         *@param A : an integer rotated sorted array
         *@param target :  an integer to be searched
         *return : an integer
         */
        public int search(int[] A, int target) {
            // write your code here
            if (A == null || A.length == 0) {
                return -1;
            }
            int start = 0;
            int end = A.length - 1;
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (A[mid] == target) {
                    return mid;
                } else if (A[start] <= A[mid]) {//**红段
                    if (A[start] <= target && target <= A[mid]){//红的上边1
                        end = mid;
                    } else {//红的下边2
                        start = mid;
                    }
                } else {//绿段
                    if (A[mid] <= target && target <= A[end]) {//绿的下边3
                        start = mid;
                    } else {//绿的上边4
                        end = mid;
                    }
                }
            }
            if (A[start] == target) {
                return start;
            }
            if (A[end] == target) {
                return end;
            }
            return -1;
        }
    }
    View Code

    四、二分答案Binary Search on Result

    不是数组让你二分, 而且题目压根看不出来是个二分法可以做的题 同样是找到满足某个条件的最大或者最小值

    1)x的平方根(http://www.lintcode.com/zh-cn/problem/sqrtx/):实现 int sqrt(int x) 函数,计算并返回 x 的平方根。

    tip:Last number that number^2 <= x

    1,ac

    class Solution {
        /**
         * @param x: An integer
         * @return: The sqrt of x
         */
        public int sqrt(int x) {
            // write your code here
            if (x < 0) {
                return -1;
            }
            if (x <= 1) {
                return x;
            }
            long start = 1, end = x;
            while (start + 1 < end) {
                long mid = start + (end - start) / 2;
                if (mid * mid <= x) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            return (int) start;
        }
    }
    View Code

    2)Wood Cut --http://www.lintcode.com/problem/wood-cut/

    ** Last/Biggest length that can get >= k pieces

    **拿最长的去切;所有答案可能在【start,end】之间,所得的切割答案mid,进行二分;如果所得的段数比k小,mid太长了,否则,mid太小,start=mid。

    1,看,待二刷

    public class Solution {
        /** 
         *@param L: Given n pieces of wood with length L[i]
         *@param k: An integer
         *return: The maximum length of the small pieces.
         */
        public int woodCut(int[] L, int k) {
            // write your code here
            //L中最大长度的确定
            int max = 0;
            for (int i = 0; i < L.length; i++) {
                max = Math.max(L[i], max);
            }
            // 二分,找到所得段最长的长度,使得能切的段数多于k,
            //start,mid,end 表示每段长度
            int start = 1;
            int end = max;
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                //如果得到的段数比k大,就把每段长度增加
                if (count(L, mid) >= k) {
                    start = mid;
                } else {
                    //如果得到的段数比k小,就把每段长度减少
                    end = mid;
                }
            }
            //边界检测
            if (count(L, start) >= k) {
                return start;
            }
            if (count(L, end) >= k) {
                return end;
            }
            return 0;
        }
        //以每段length长切割,可得到多少块
        public int count(int[] L, int length) {
            int sum = 0;
            for (int i = 0; i < L.length; i++) {
                sum += L[i] / length;
            }
            return  sum;
        }
    }
    View Code

    3)Copy Books-- http://www.lintcode.com/en/problem/copy-books/ 题意:将数组切分为k个子数组,让数组和最大的最小

    tip:将数组切分为k个子数组,让数组和最大的最小

     O(n log m)
    public class Solution {
        /**
         * @param pages: an array of integers
         * @param k: an integer
         * @return: an integer
         */
        public int copyBooks(int[] pages, int k) {
            //抄书的用时,主要看一个人最重负担的页数,该页数越小,用时越短
            // 让最重负担sum(最大子数组和),最小
            //最重负担sum的值范围【max,total】
            if (pages.length == 0) {
                return 0;
            }
            int max = pages[0];
            int total = 0;
            for (int i = 0; i < pages.length; i++) {
                total += pages[i];
                if (max < pages[i]) {
                    max = pages[i];
                }
            }
            int start = max;
            int end = total;
            while(start + 1 < end) {
                //mid 为最重负担
                int mid = start + (end - start) / 2;
                if (countCopiers(pages, mid) > k) {//抄书人多余k,需要加重抄书负担
                    start = mid;
                } else {//否则减轻工作量
                    end = mid;
                }
            }
            if (countCopiers(pages, start) <= k) {
                return start;
            }
            return end;
        }
        //limit为一个人最大的工作量,在当前工作量下,需要几个抄书人
        private int countCopiers(int[] pages, int limit) {
            //sum 为 1个人的工作量,当工作量>limit时,需要另加一人抄书
            int sum = pages[0];
            //limit下,需要1人
            int copiers = 1;
            for (int i = 1; i < pages.length; i++) {
                if (sum + pages[i] > limit) {//保证当前工作量都不能多余limit,加人
                    copiers++;
                    sum = 0;//清空sum,继续计算下个人的工作量
                }
                sum += pages[i]; //sum计算1个人的工作量
            }
            return copiers;
        }
    }
    View Code

    --联想阿里编程题待续:https://bbs.byr.cn/#!article/Java/55292

    待刷:related如下:




    2017-03-0722:23:49

    搜索插入位置:http://www.lintcode.com/zh-cn/problem/search-insert-position/

    Binary Search: 、

    • http://www.lintcode.com/problem/search-insert-position/

    • http://www.lintcode.com/problem/count-of-smaller-number/

    • http://www.lintcode.com/problem/search-for-a-range/

    Rotate Array

    •http://www.lintcode.com/problem/recover-rotated-sorted-array/

    • http://www.lintcode.com/problem/rotate-string/

    • 三步翻转法: • [4,5,1,2,3] → [5,4,1,2,3] → [5,4,3,2,1] → [1,2,3,4,5]

    排序数组中最接近元素:http://www.lintcode.com/zh-cn/problem/closest-number-in-sorted-array/#

    public class Solution {
        /**
         * @param A an integer array sorted in ascending order
         * @param target an integer
         * @return an integer
         */
        public int closestNumber(int[] A, int target) {
            // Write your code here
            if (A == null || A.length == 0) {
                return -1;
            }
            int index = firstIndex(A, target);
            if (index == 0) {
                return 0;
            }
            if (index == A.length - 1) {
                return index;
            }
            if (target - A[index -1] > A[index] - target) {
                return index;
            } else {
                return index - 1;
            }
        }
        
        public int firstIndex(int [] A, int target) {
            int start = 0;
            int end = A.length - 1;
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (A[mid] < target) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            if (A[start] >= target) {
                return start;
            }
            if (A[end] >= target) {
                return end;
            }
            return A.length - 1; 
        }
    }
    View Code
    public class Solution {
        /**
         * @param A an integer array sorted in ascending order
         * @param target an integer
         * @return an integer
         */
        public int closestNumber(int[] A, int target) {
            // Write your code here
            int start = 0;
            int end = A.length;
            int min = Integer.MAX_VALUE;
            while(start + 1 < end) {
                int mid = start + (end - start) / 2;
                int dis = 0;
                dis = Math.abs(A[mid] - target);
                if (A[mid] == target) {
                    end = mid;
                } else if (A[mid] < target) {
                    start = mid;
                } else {
                    end = mid;
                }
                if (dis < min) {
                    min = dis;
                }
            
            }
            if (Math.abs(A[start]- target) <= min ) {
                return start;
            } 
            if (Math.abs(A[end]- target) <= min) {
                return end;
            }
            return A.length - 1;
        }
    }
    View Code myown

    Smallest Rectangle Enclosing Black Pixels :http://www.lintcode.com/zh-cn/problem/smallest-rectangle-enclosing-black-pixels/

    public class Solution {
        /**
         * @param image a binary matrix with '0' and '1'
         * @param x, y the location of one of the black pixels
         * @return an integer
         */
        public int minArea(char[][] image, int x, int y) {
            // Write your code here
            if (image == null || image.length == 0 || image[0].length == 0) {
                return 0;
            }
            int m = image.length;
            int n = image[0].length;
            int left = findLeft(image, 0, y);
            int right = findRight(image,y,n - 1);
            int top = findTop(image, 0, x);
            int bottom = findBottom(image, x, m - 1);
            return (right - left + 1) * (bottom - top + 1);
        }
        private int findLeft(char[][] image, int start, int end){
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (isEmptyCol(image, mid)) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            if (isEmptyCol(image, start)) {
                return end;
            }
            return start;
        }
        private int findRight(char[][] image, int start, int end){
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (isEmptyCol(image, mid)) {
                    end = mid;
                } else {
                    start = mid;
                }
            }
            if (isEmptyCol(image, end)) {
                return start;
            }
            return end;
        }
        private int findTop(char[][] image, int start, int end){
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (isEmptyRow(image, mid)) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
            if (isEmptyRow(image, start)) {
                return end;
            }
            return start;
        }
        private int findBottom(char[][] image, int start, int end){
            while (start + 1 < end) {
                int mid = start + (end - start) / 2;
                if (isEmptyRow(image, mid)) {
                    end = mid;
                } else {
                    start = mid;
                }
            }
            if (isEmptyRow(image, end)) {
                return start;
            }
            return end;
        }
        private boolean isEmptyCol(char[][] image, int col){
            for (int i = 0; i <= image.length - 1; i++) {
                if (image[i][col] == '1') {
                    return false;
                }
            }
            return true;
        }
        private boolean isEmptyRow(char[][] image, int com){
            for (int i = 0; i <= image[0].length - 1; i++) {
                if (image[com][i] == '1') {
                    return false;
                }
            }
            return true;
        }
    }
    View Code
  • 相关阅读:
    使用C39HrP48DhTt字體生成條型碼
    GUI設計禁忌
    music
    AADL的四种经典设计模式
    Model to Text工具Acceleo使用教程(七)——模板服务
    Model to Text工具Acceleo使用教程(二)——体系结构
    Model to Text工具Acceleo使用教程——背景知识
    P/NP/NPC/NPhard概念的图形解释
    哥德巴赫猜想穷举验证算法及实现
    Model to Text工具Acceleo使用教程(五)——模板服务
  • 原文地址:https://www.cnblogs.com/lingli-meng/p/6495815.html
Copyright © 2011-2022 走看看