算法题总结以及答案

  • 两数之和
    给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
    你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
    示例:
    给定 nums = [2, 7, 11, 15], target = 9
    因为 nums[0] + nums[1] = 2 + 7 = 9
    所以返回 [0, 1]
    解答:
 public static int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        for(int i = 0; i< nums.length; i++) {
            if(map.containsKey(target - nums[i])) {
                return new int[] {map.get(target-nums[i]),i};
            }
            map.put(nums[i], i);
        }
        throw new IllegalArgumentException("No two sum solution");
    }

    public static void main(String[] args) {
        int[] a = {2,7,11,15};
        int[] m = twoSum(a,9);
        for (int k : m) {

        System.out.println(k+"");
        }
    }
  • 两数相加
    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
    如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
    您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
    示例:
    输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
    输出:7 -> 0 -> 8
    原因:342 + 465 = 807
    解答:
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode pre = new ListNode(0);
        ListNode cur = pre;
        int carry = 0;
        while(l1 != null || l2 != null) {
            int x = l1 == null ? 0 : l1.val;
            int y = l2 == null ? 0 : l2.val;
            int sum = x + y + carry;
            
            carry = sum / 10;
            sum = sum % 10;
            cur.next = new ListNode(sum);

            cur = cur.next;
            if(l1 != null)
                l1 = l1.next;
            if(l2 != null)
                l2 = l2.next;
        }
        if(carry == 1) {
            cur.next = new ListNode(carry);
        }
        return pre.next;
    }
  • 无重复字符的最长子串
    给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
    示例 1:
    输入: “abcabcbb”
    输出: 3
    解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
    示例 2:
    输入: “bbbbb”
    输出: 1
    解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
    解答:
public static int lengthOfLongestSubstring(String s) {
        int n = s.length(), ans = 0;
        Map<Character, Integer> map = new HashMap<>();
        for (int end = 0, start = 0; end < n; end++) {
            char alpha = s.charAt(end);
            if (map.containsKey(alpha)) {
                start = Math.max(map.get(alpha), start);
            }
            ans = Math.max(ans, end - start + 1);
            map.put(s.charAt(end), end + 1);
        }
        return ans;
    }

    public static void main(String[] args) {
        System.out.println(lengthOfLongestSubstring("abababaccccabcbbb"));
    }
  • 寻找两个有序数组的中位数
    给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
    请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
    你可以假设 nums1 和 nums2 不会同时为空。
    示例 1:
    nums1 = [1, 3]
    nums2 = [2]
    则中位数是 2.0
    示例 2:
    nums1 = [1, 2]
    nums2 = [3, 4]
    则中位数是 (2 + 3)/2 = 2.5
    解答:
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int[] nums;
        int m = nums1.length;
        int n = nums2.length;
        nums = new int[m + n];
        if (m == 0) {
            if (n % 2 == 0) {
                return (nums2[n / 2 - 1] + nums2[n / 2]) / 2.0;
            } else {

                return nums2[n / 2];
            }
        }
        if (n == 0) {
            if (m % 2 == 0) {
                return (nums1[m / 2 - 1] + nums1[m / 2]) / 2.0;
            } else {
                return nums1[m / 2];
            }
        }

        int count = 0;
        int i = 0, j = 0;
        while (count != (m + n)) {
            if (i == m) {
                while (j != n) {
                    nums[count++] = nums2[j++];
                }
                break;
            }
            if (j == n) {
                while (i != m) {
                    nums[count++] = nums1[i++];
                }
                break;
            }

            if (nums1[i] < nums2[j]) {
                nums[count++] = nums1[i++];
            } else {
                nums[count++] = nums2[j++];
            }
        }

        if (count % 2 == 0) {
            return (nums[count / 2 - 1] + nums[count / 2]) / 2.0;
        } else {
            return nums[count / 2];
        }
    }
  • 设计一个算法,计算出n阶乘中尾部零的个数
    样例 1:
    输入: 11
    输出: 2
    样例解释:
    11! = 39916800, 结尾的0有2个。
    样例 2:
    输入: 5
    输出: 1
    样例解释:
    5! = 120, 结尾的0有1个。
    解答:
public long trailingZeros(long n) {
        long sum = 0;
        while (n != 0) {
            sum += n / 5;
            n /= 5;
        }
        return sum;
    }
  • 二分查找
    给定一个排序的整数数组(升序)和一个要查找的整数target,用O(logn)的时间查找到target第一次出现的下标(从0开始),如果target不存在于数组中,返回-1
样例  1:
	输入:[1,4,4,5,7,7,8,9,9,10],1
	输出: 0
	样例解释: 
	第一次出现在第0个位置。
样例 2:
	输入: [1, 2, 3, 3, 4, 5, 10],3
	输出: 2
	样例解释: 
	第一次出现在第2个位置
样例 3:
	输入: [1, 2, 3, 3, 4, 5, 10],6
	输出: -1	
	样例解释: 
	没有出现过6, 返回-1

解答:

  /**
     * 二分查找
     * @param nums
     * @param target
     * @return
     */
    public static int binarySearch(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return -1;
        }

        int start = 0, end = nums.length - 1;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (nums[mid] == target) {
                end = mid;
            } else if (nums[mid] < target) {
                start = mid;
                // or start = mid + 1
            } else {
                end = mid;
                // or end = mid - 1
            }
        }

        if (nums[start] == target) {
            return start;
        }
        if (nums[end] == target) {
            return end;
        }
        return -1;
    }
  • 旋转字符串
    给定一个字符串(以字符数组的形式给出)和一个偏移量,根据偏移量原地旋转字符串(从左向右旋转)
    样例 1:
    输入: str=“abcdefg”, offset = 3
    输出: str = “efgabcd”
    样例解释: 注意是原地旋转,即str旋转后为"efgabcd"
    样例 2:
    输入: str=“abcdefg”, offset = 0
    输出: str = “abcdefg”
    样例解释: 注意是原地旋转,即str旋转后为"abcdefg"
    样例 3:
    输入: str=“abcdefg”, offset = 1
    输出: str = “gabcdef”
    样例解释: 注意是原地旋转,即str旋转后为"gabcdef"
    解答:
public static char[] rotateString(char[] str, int offset) {
        // write your code here
        if (str == null || str.length == 0){
            return str;
        }
        offset = offset % str.length;
        if (offset == 0){
            return str;
        }
        int index = str.length - (offset);
        int indexB = index;
        StringBuffer sbf = new StringBuffer();
        for (int i = 0; i < str.length; i++) {
            if (i < offset || i < indexB){
                sbf.append(str[i]); //保存不需要翻转的全部字符
                if (i < offset){    //将后面需要翻转的字符进行翻转
                    str[i] = str[index];
                    index++;
                }
            }else {
                break;
            }
        }
        for (int j = 0; j < sbf.length(); j++) {	//将之前保存的字符按顺序放入位置
            char c = sbf.toString().charAt(j);
            if (offset+j < str.length){
                str[offset+j] = c;
            }
        }

        return str;
    }
  • 字符串查找
    对于一个给定的 source 字符串和一个 target 字符串,你应该在 source 字符串中找出 target 字符串出现的第一个位置(从0开始)。如果不存在,则返回 -1。
    在面试中我是否需要实现KMP算法?
    不需要,当这种问题出现在面试中时,面试官很可能只是想要测试一下你的基础应用能力。当然你需要先跟面试官确认清楚要怎么实现这个题。
    样例
    样例 1:
    输入: source = “source” , target = “target”
    输出:-1
    样例解释: 如果source里没有包含target的内容,返回-1
    样例 2:
    输入: source = “abcdabcdefg” ,target = “bcd”
    输出: 1
    样例解释: 如果source里包含target的内容,返回target在source里第一次出现的位置
    解答:
public int strStr(String source, String target) {
        if (source == null || target == null) {
            return -1;
        }

        for (int i = 0; i < source.length() - target.length() + 1; i++) {
            int j = 0;
            for (j = 0; j < target.length(); j++) {
                if (source.charAt(i + j) != target.charAt(j)) {
                    break;
                }
            }
            // finished loop, target found
            if (j == target.length()) {
                return i;
            }
        }
        return -1;
    }

另外解法:

public int strStr2(String source, String target) {
        if(target == null) {
            return -1;
        }
        int m = target.length();
        if(m == 0 && source != null) {
            return 0;
        }
        
        if(source == null) {
            return -1;
        }
        int n = source.length();
        if(n == 0) {
            return -1;
        }

        // mod could be any big integer
        // just make sure mod * 33 wont exceed max value of int.
        int mod = Integer.MAX_VALUE / 33;
        int hash_target = 0;

        // 33 could be something else like 26 or whatever you want
        for (int i = 0; i < m; ++i) {
            hash_target = (hash_target * 33 + target.charAt(i) - 'a') % mod;
            if (hash_target < 0) {
                hash_target += mod;
            }
        }

        int m33 = 1;
        for (int i = 0; i < m - 1; ++i) {
            m33 = m33 * 33 % mod;
        }

        int value = 0;
        for (int i = 0; i < n; ++i) {
            if (i >= m) {
                value = (value - m33 * (source.charAt(i - m) - 'a')) % mod;
            }

            value = (value * 33 + source.charAt(i) - 'a') % mod;
            if (value < 0) {
                value += mod;
            }

            if (i >= m - 1 && value == hash_target) {
                // you have to double check by directly compare the string
                if (target.equals(source.substring(i - m + 1, i + 1))) {
                    return i - m + 1;
                }
            }
        }
        return -1;
    }
  • 合并排序数组
    合并两个有序升序的整数数组A和B变成一个新的数组。新数组也要有序。
    样例 1:
    输入: A=[1], B=[1]
    输出:[1,1]
    样例解释: 返回合并后的数组。
    样例 2:
    输入: A=[1,2,3,4], B=[2,4,5,6]
    输出: [1,2,2,3,4,4,5,6]
    样例解释: 返回合并后的数组。
    解答:
/**
     * 使用两个指针分别对数组从小到大遍历,每次取二者中较小的放在新数组中。
     * 直到某个指针先到结尾,另一个数组中剩余的数字直接放在新数组后面。
     * 时间复杂度O(n)
     */
    public int[] mergeSortedArray(int[] A, int[] B) {
        if (A == null || B == null) {
            return null;
        }

        int[] result = new int[A.length + B.length];
        int i = 0, j = 0, index = 0;

        while (i < A.length && j < B.length) {
            if (A[i] < B[j]) {
                result[index++] = A[i++];
            } else {
                result[index++] = B[j++];
            }
        }

        while (i < A.length) {
            result[index++] = A[i++];
        }
        while (j < B.length) {
            result[index++] = B[j++];
        }

        return result;
    }
  • 平面列表
    给定一个列表,该列表中的每个元素要么是个列表,要么是整数。将其变成一个只包含整数的简单列表。
    样例 1:
    输入: [[1,1],2,[1,1]]
    输出:[1,1,2,1,1]
    样例解释:
    将其变成一个只包含整数的简单列表。
    样例 2:
    输入: [1,2,[1,2]]
    输出:[1,2,1,2]
    样例解释:
    将其变成一个只包含整数的简单列表。
    样例 3:
    输入:[4,[3,[2,[1]]]]
    输出:[4,3,2,1]
    样例解释:
    将其变成一个只包含整数的简单列表。
    解答:
public List<Integer> flatten(List<NestedInteger> nestedList) {
        // Write your code here
        List<Integer> result = new ArrayList<Integer>();
        for (NestedInteger ele : nestedList)
            if (ele.isInteger())
                result.add(ele.getInteger());
            else
                result.addAll(flatten(ele.getList()));
        return result;
    }
}

public List<Integer> flatten(List<NestedInteger> nestedList) {
        boolean isFlat = true;
        List<NestedInteger> ls = nestedList;
        while (isFlat) {
            isFlat = false;
            List<NestedInteger> newLs = new ArrayList<>();
            for (NestedInteger ni : ls) {
                if (ni.isInteger()) {
                    newLs.add(ni);
                } else {
                    newLs.addAll(ni.getList());
                    isFlat = true;
                }
            }
            ls = newLs;
        }
        List<Integer> r = new ArrayList<>();
        for (NestedInteger ni : ls) {
            r.add(ni.getInteger());
        }
        return r;
    }
  • 有效的三角形
    给出三个整数 a, b, c, 如果它们可以构成三角形,返回 true
    样例 1:
    输入 : a = 2, b = 3, c = 4
    输出 : true
    样例 2:
    输入 : a = 1, b = 2, c = 3
    输出 : false
    解答:
public boolean isValidTriangle(int a, int b, int c) {
        // write your code here
        return (a + b > c && b + c > a && c + a > b);
    }
  • 三数之和
    给定一个n个整数的数组和一个目标整数target,找到下标为i、j、k的数组元素0 <= i < j < k < n,满足条件nums[i] + nums[j] + nums[k] < target.
    样例1
    输入: nums = [-2,0,1,3], target = 2
    输出: 2
    解释:
    因为有两种三个元素之和,它们的和小于2:
    [-2, 0, 1]
    [-2, 0, 3]
    样例2
    输入: nums = [-2,0,-1,3], target = 2
    输出: 3
    解释:
    因为有三种三个元素之和,它们的和小于2:
    [-2, 0, 1]
    [-2, 0, 3]
    [-2, -1, 3]
    解答:
public int threeSumSmaller(int[] nums, int target) {
        // Write your code here
        int ans = 0;
        Arrays.sort(nums);
        int len = nums.length;
        for(int i = 0; i < len - 2; i++) {
            int left = i + 1, right = len - 1;
            while(left < right) {
                if(nums[i] + nums[left] + nums[right] < target) {
                    ans += right-left;
                    left++;
                } else {
                    right--;
                }
            }
        }
        return ans;
    }
  • 最大子数组
    给定一个整数数组,找到一个具有最大和的子数组,返回其最大和。
    样例1:
    输入:[−2,2,−3,4,−1,2,1,−5,3]
    输出:6
    解释:符合要求的子数组为[4,−1,2,1],其最大和为 6。
    样例2:
    输入:[1,2,3,4]
    输出:10
    解释:符合要求的子数组为[1,2,3,4],其最大和为 10
public int maxSubArray(int[] A) {
        if (A == null || A.length == 0){
            return 0;
        }
        //max记录全局最大值,sum记录区间和,如果当前sum>0,那么可以继续和后面的数求和,否则就从0开始
        int max = Integer.MIN_VALUE, sum = 0;
        for (int i = 0; i < A.length; i++) {
            sum += A[i];
            max = Math.max(max, sum);
            sum = Math.max(sum, 0);
        }

        return max;
    }
  • 主元素
    给定一个整型数组,找出主元素,它在数组中的出现次数严格大于数组元素个数的二分之一
    样例 1:
    输入: [1, 1, 1, 1, 2, 2, 2]
    输出: 1
    样例 2:
    输入: [1, 1, 1, 2, 2, 2, 2]
    输出: 2
    解答:
public int majorityNumber(List<Integer> nums) {
        
        int currentMajor = 0;
        int count = 0;
        
        for(Integer num : nums) {
            if(count == 0) {
                currentMajor = num;
            }
            
            if(num == currentMajor) {
                count++;
            } else {
                count--;
                
            }
        }
        
        return currentMajor;
    }
}
  • 比较字符串
    比较两个字符串A和B,确定A中是否包含B中所有的字符。字符串A和B中的字符都是 大写字母.
    给出 A = “ABCD” B = “ACD”,返回 true
    给出 A = “ABCD” B = “AABC”, 返回 false
    解答:
public static  boolean compareStrings(String A, String B) {
        //counts首先记录A中所有的字符以及它们的个数,然后遍历B,如果出现counts[i]小于0的情况,说明B中该字符出现的次数
        //大于在A中出现的次数
        int[] counts = new int[26];
        for (int i = 0; i < 26; i++) {
            counts[i] = 0;
        }
        for (int i = 0; i < A.length(); i++) {
            counts[A.charAt(i) - 'A'] ++;
        }
        for (int i = 0; i < B.length(); i++) {
            counts[B.charAt(i) - 'A'] --;
            if (counts[B.charAt(i) - 'A'] < 0) {
                return false;
            }
        }
        return true;
    }
  • 搜索插入位置
    给定一个排序数组和一个目标值,如果在数组中找到目标值则返回索引。如果没有,返回到它将会被按顺序插入的位置。
    你可以假设在数组中无重复元素。
    样例
    [1,3,5,6],5 → 2
    [1,3,5,6],2 → 1
    [1,3,5,6], 7 → 4
    [1,3,5,6],0 → 0
    解答:
public int searchInsert(int[] A, int target) {
        if (A == null || A.length == 0) {
            return 0;
        }
        int start = 0, end = A.length - 1;
        
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (A[mid] == target) {
                return mid;
            } else if (A[mid] < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
        
        if (A[start] >= target) {
            return start;
        } else if (A[end] >= target) {
            return end;
        } else {
            return end + 1;
        }
    }
}

public int searchInsert(int[] A, int target) {
        if (A == null || A.length == 0) {
            return 0;
        }
        int start = 0;
        int end = A.length - 1;
        int mid;
        
        if (target < A[0]) {
            return 0;
        }
        // find the last number less than target
        while (start + 1 < end) {
            mid = start + (end - start) / 2;
            if (A[mid] == target) {
                return mid;
            } else if (A[mid] < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
        
        if (A[end] == target) {
            return end;
        }
        if (A[end] < target) {
            return end + 1;
        }
        if (A[start] == target) {
            return start;
        }
        return start + 1;
    }
  • 二叉树的层次遍历
    给出一棵二叉树,返回其节点值的层次遍历(逐层从左往右访问)
样例 1:
输入:{1,2,3}
输出:[[1],[2,3]]
解释:
   1
  / \
 2   3
它将被序列化为{1,2,3}
层次遍历
样例 2:
输入:{1,#,2,3}
输出:[[1],[2],[3]]
解释:
1
 \
  2
 /
3
它将被序列化为{1,#,2,3}
层次遍历

解答:

/**
     * 二叉树的层次遍历通常实现方式为使用队列不断压入节点遍历,每次取出队列首个元素遍历左右子节点,
     * 继续压入子节点即可
     */
    public static List<List<Integer>> levelOrder(TreeNode root) {
        List result = new ArrayList();

        if (root == null) {
            return result;
        }

        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);

        while (!queue.isEmpty()) {
            ArrayList<Integer> level = new ArrayList<Integer>();
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode head = queue.poll();
                level.add(head.val);
                if (head.left != null) {
                    queue.offer(head.left);
                }
                if (head.right != null) {
                    queue.offer(head.right);
                }
            }
            result.add(level);
        }

        return result;
    }

    public List<List<Integer>> levelOrder2(TreeNode root) {
        List<List<Integer>> results = new ArrayList<List<Integer>>();

        if (root == null) {
            return results;
        }

        int maxLevel = 0;
        while (true) {
            List<Integer> level = new ArrayList<Integer>();
            dfs(root, level, 0, maxLevel);
            if (level.size() == 0) {
                break;
            }

            results.add(level);
            maxLevel++;
        }

        return results;
    }

    private void dfs(TreeNode root,
                     List<Integer> level,
                     int curtLevel,
                     int maxLevel) {
        if (root == null || curtLevel > maxLevel) {
            return;
        }

        if (curtLevel == maxLevel) {
            level.add(root.val);
            return;
        }
        dfs(root.left, level, curtLevel + 1, maxLevel);
        dfs(root.right, level, curtLevel + 1, maxLevel);

    }
  • 冒泡排序
    a、冒泡排序,是通过每一次遍历获取最大/最小值
    b、将最大值/最小值放在尾部/头部
    c、然后除开最大值/最小值,剩下的数据在进行遍历获取最大/最小值
    d、代码实现
    解答:
public static void main(String[] args) {

        int arr[] = {8, 5, 3, 2, 4};

        //冒泡
        for (int i = 0; i < arr.length; i++) {
            //外层循环,遍历次数
            for (int j = 0; j < arr.length - i - 1; j++) {
                //内层循环,升序(如果前一个值比后一个值大,则交换)
                //内层循环一次,获取一个最大值
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j + 1];
                    arr[j + 1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }
  • 选择排序
    a、将第一个值看成最小值
    b、然后和后续的比较找出最小值和下标
    c、交换本次遍历的起始值和最小值
    d、说明:每次遍历的时候,将前面找出的最小值,看成一个有序的列表,后面的看成无序的列表,然后每次遍历无序列表找出最小值。
    e、代码实现
    解答:
public static void main(String[] args) {

        int arr[] = {6, 5, 3, 2, 4};

        //选择
        for (int i = 0; i < arr.length; i++) {
            //默认第一个是最小的。
            int min = arr[i];
            //记录最小的下标
            int index = i;
            //通过与后面的数据进行比较得出,最小值和下标
            for (int j = i + 1; j < arr.length; j++) {
                if (min > arr[j]) {
                    min = arr[j];
                    index = j;
                }
            }
            //然后将最小值与本次循环的,开始值交换
            int temp = arr[i];
            arr[i] = min;
            arr[index] = temp;
            //说明:将i前面的数据看成一个排好的队列,i后面的看成一个无序队列。每次只需要找无需的最小值,做替换
        }
    }
  • 插入排序
    a、默认从第二个数据开始比较。
     b、如果第二个数据比第一个小,则交换。然后在用第三个数据比较,如果比前面小,则插入(狡猾)。否则,退出循环
    c、说明:默认将第一数据看成有序列表,后面无序的列表循环每一个数据,如果比前面的数据小则插入(交换)。否则退出。
    d、代码实现
    解答:
public static void main(String[] args) {

        int arr[] = {7, 5, 3, 2, 4};

        //插入排序
        for (int i = 1; i < arr.length; i++) {
            //外层循环,从第二个开始比较
            for (int j = i; j > 0; j--) {
                //内存循环,与前面排好序的数据比较,如果后面的数据小于前面的则交换
                if (arr[j] < arr[j - 1]) {
                    int temp = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = temp;
                } else {
                    //如果不小于,说明插入完毕,退出内层循环
                    break;
                }
            }
        }
    }
  • 希尔排序(插入排序变种版)
    a、基本上和插入排序一样的道理
    b、不一样的地方在于,每次循环的步长,通过减半的方式来实现
    c、说明:基本原理和插入排序类似,不一样的地方在于。通过间隔多个数据来进行插入排序。
    解答:
public static void main(String[] args) {

        int arr[] = {7, 5, 3, 2, 4};

        //希尔排序(插入排序变种版)
        for (int i = arr.length / 2; i > 0; i /= 2) {
            //i层循环控制步长
            for (int j = i; j < arr.length; j++) {
                //j控制无序端的起始位置
                for (int k = j; k > 0  && k - i >= 0; k -= i) {
                    if (arr[k] < arr[k - i]) {
                        int temp = arr[k - i];
                        arr[k - i] = arr[k];
                        arr[k] = temp;
                    } else {
                        break;
                    }
                }
            }
            //j,k为插入排序,不过步长为i
        }
    }
  • 快速排序
    a、确认列表第一个数据为中间值,第一个值看成空缺(低指针空缺)。
    b、然后在剩下的队列中,看成有左右两个指针(高低)。
    c、开始高指针向左移动,如果遇到小于中间值的数据,则将这个数据赋值到低指针空缺,并且将高指针的数据看成空缺值(高指针空缺)。然后先向右移动一下低指针,并且切换低指针移动。
    d、当低指针移动到大于中间值的时候,赋值到高指针空缺的地方。然后先高指针向左移动,并且切换高指针移动。重复c、d操作。
    e、直到高指针和低指针相等时退出,并且将中间值赋值给对应指针位置。
    f、然后将中间值的左右两边看成行的列表,进行快速排序操作。
public static void main(String[] args) {

        int arr[] = {7, 5, 3, 2, 4, 1, 8, 9, 6};

        //快速排序
        int low = 0;
        int high = arr.length - 1;
        quickSort(arr, low, high);  
    }

    public static void quickSort(int[] arr, int low, int high) {
        //如果指针在同一位置(只有一个数据时),退出
        if (high - low < 1) {
            return;
        }
        //标记,从高指针开始,还是低指针(默认高指针)
        boolean flag = true;
        //记录指针的其实位置
        int start = low;
        int end = high;
        //默认中间值为低指针的第一个值
        int midValue = arr[low];
        while (true) {
            //高指针移动
            if (flag) {
                //如果列表右方的数据大于中间值,则向左移动
                if (arr[high] > midValue) {
                    high--;
                } else if (arr[high] < midValue) {
                    //如果小于,则覆盖最开始的低指针值,并且移动低指针,标志位改成从低指针开始移动
                    arr[low] = arr[high];
                    low++;
                    flag = false;
                }
            } else {
                //如果低指针数据小于中间值,则低指针向右移动
                if (arr[low] < midValue) {
                    low++;
                } else if (arr[low] > midValue) {
                    //如果低指针的值大于中间值,则覆盖高指针停留时的数据,并向左移动高指针。切换为高指针移动
                    arr[high] = arr[low];
                    high--;
                    flag = true;
                }
            }
            //当两个指针的位置相同时,则找到了中间值的位置,并退出循环
            if (low == high) {
                arr[low] = midValue;
                break;
            }
        }
        //然后出现有,中间值左边的小于中间值。右边的大于中间值。
        //然后在对左右两边的列表在进行快速排序
        quickSort(arr, start, low -1);
        quickSort(arr, low + 1, end);
    }
  • 归并排序
    a、将列表按照对等的方式进行拆分
    b、拆分小最小快的时候,在将最小块按照原来的拆分,进行合并
    c、合并的时候,通过左右两块的左边开始比较大小。小的数据放入新的块中
    d、说明:简单一点就是先对半拆成最小单位,然后将两半数据合并成一个有序的列表。
    解答:
public static void main(String[] args) {

        int arr[] = {7, 5, 3, 2, 4, 1,6};

        //归并排序
        int start = 0;
        int end = arr.length - 1;
        mergeSort(arr, start, end);
    }

    public static void mergeSort(int[] arr, int start, int end) {
        //判断拆分的不为最小单位
        if (end - start > 0) {
            //再一次拆分,知道拆成一个一个的数据
            mergeSort(arr, start, (start + end) / 2);
            mergeSort(arr, (start + end) / 2 + 1, end);
            //记录开始/结束位置
            int left = start;
            int right = (start + end) / 2 + 1;
            //记录每个小单位的排序结果
            int index = 0;
            int[] result = new int[end - start + 1];
            //如果查分后的两块数据,都还存在
            while (left <= (start + end) / 2 && right <= end) {
                //比较两块数据的大小,然后赋值,并且移动下标
                if (arr[left] <= arr[right]) {
                    result[index] = arr[left];
                    left++;
                } else {
                    result[index] = arr[right];
                    right++;
                }
                //移动单位记录的下标
                index++;
            }
            //当某一块数据不存在了时
            while (left <= (start + end) / 2 || right <= end) {
                //直接赋值到记录下标
                if (left <= (start + end) / 2) {
                    result[index] = arr[left];
                    left++;
                } else {
                    result[index] = arr[right];
                    right++;
                }
                index++;
            }
            //最后将新的数据赋值给原来的列表,并且是对应分块后的下标。
            for (int i = start; i <= end; i++) {
                arr[i] = result[i - start];
            }
        }
    }
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值