LeetCode刷题之分治算法

在计算机科学中,分治法是构建基于多项分支递归的一种很重要的算法范式。字面上的解释是「分而治之」,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

分治算法的步骤:

1、分:将一个问题切分为两个或两个以上的子问题。
2、治:处理每一个子问题。
2、并:汇总合并所有子问题的结果得出最终的答案。

LeetCode刷题之分治算法_第1张图片

这个技巧是很多高效算法的基础,如排序算法(快速排序、归并排序)、傅立叶变换(快速傅立叶变换)、汉诺塔问题。

剑指 Offer 25. 合并两个排序的链表

输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

示例1:

输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

题解:
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    /**
     * 思路:
     * 创建一个新头节点preNode,比较l1和l2,preNode指向小的节点
     * 然后将小的节点往后移动一个,将preNode往后移动一个,继续比较l1和l2
     * 直到l1或者l2某一个为null,那么一种一个合并完,然后将preNode指向另一个非空节点
     * @param l1
     * @param l2
     * @return
     */
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode preNode = new ListNode(-1);
        ListNode head = preNode;
        while (l1!=null && l2!=null) {
            if (l1.val <= l2.val) {
                //取l1的节点作为新节点的首节点
                preNode.next = l1;
                //往后移动节点
                l1 = l1.next;
            } else {
                //取l2的节点作为新节点的首节点
                preNode.next = l2;
                //往后移动节点
                l2 = l2.next;
            }
            //preNode往后移以用来保存新的节点
            preNode = preNode.next;
        }
        //当某个链表为空,非空链表剩下节点拼接在head链表的末尾
        preNode.next = l1==null?l2:l1;

        return head.next;
    }
}

169. 多数元素

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入: [3,2,3]
输出: 3

题解:
class Solution {
    public int majorityElement(int[] nums) {
        Map table = new HashMap<>();
        for (int num : nums) {
            //将当前数字出现次数+1
            if (!table.containsKey(num)) {
                table.put(num, 1);
            } else {
                table.put(num, table.get(num) + 1);
            }
        }
        Set> entries = table.entrySet();
        for (Map.Entry entry : entries) {
            if (entry.getValue() * 2 > nums.length) {
                //满足条件
                return entry.getKey();
            }
        }
        return 0;
    }
}

53. 最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

题解:
class Solution {
    /**
     * 思路:
     * 状态定义: 设动态规划列表dp ,dp[i]代表以元素nums[i]为结尾的连续子数组最大和。
     *
     * ​我们发现dp[i]就是以数组下标为i的数做为结尾的最大子序列和,
     * 注意是以i为结尾,比如说现在有一个数组{6,-3,-2,7,-15,1,2,2},为了不搞,我们就下标以1开始,dp[3]就是以-2为结尾的,
     * 那么显然dp[3]的最大值就是1咯(6,-3,-2),dp[4]要以7结尾那么以7结尾的子序列最大和就是8(6,-3,-2,7)。
     *
     * ​ 知道dp[i]是啥后,现在我们开始细细品一下上面这个递推式,求dp[i]的时候是不是有两种可能,
     * 要么就是像上面的dp[4]一样,dp[3]求出来是1了,再加上自己array[4]是最大的,那么还有一种可能就是说如果dp[3]我求出来是-100,
     * 那如果我也是dp[3]+array[4]的话是-93,这时候dp[3]反而是累赘,最大就是自己(因为前面定义了必须以i为结尾,也就说必须以7结尾)。
     *
     * @param nums
     * @return
     */
    public int maxSubArray(int[] nums) {
        int[] dp = new int[nums.length];
        dp[0] = nums[0];
        int max = dp[0];
        for (int i=1;i max) {
                max = dp[i];
            }
        }
        return max;
    }
}

你可能感兴趣的:(LeetCode刷题之分治算法)