leetcode 算法整理

一 字符串中的最大回文串(第5题)

Given a string s, find the longest palindromic substring in s. You may assume that the maximum length of sis 1000.

Example:

Input: "babad"

Output: "bab"

Note: "aba" is also a valid answer.

 

Example:

Input: "cbbd"

Output: "bb"

 

1. 我的解法(accepted): 中心扩展

思路: 回文即代表有中心,一次遍历中,对于每个位置上的数字求一下最大的回文串即可,初始处理剪枝,合并掉同样的元素,如xxxxaaaxxxx,先常量级别把a合并掉; 遍历时候再次剪枝,遍历过的有一个maxLen,如果即将遍历的元素最大可能回文长度都不可能超过maxLen,不再遍历。

 1 public class Test1218 {
 2 
 3     public static void main(String[] args) {
 4         String str = "ababababa";
 5         System.out.println(longestPalindrome(str));
 6 
 7     }
 8 
 9     public static String longestPalindrome(String s) {
10         if (s == null) {
11             return null;
12         }
13         char[] chars = s.toCharArray();
14         int length = chars.length;
15         int maxLen = 0;
16         String maxStr = "";
17 
18         for (int i = 0; i < length; i++) {
19 
20             // cut branch
21             int possibleLength = getMaxPossibleLength(i, length);
22             if (possibleLength < maxLen) {
23                 continue;
24             }
25 
26             String maxStrTmp = getMaxStrByIndex(i, chars);
27             if (maxLen < maxStrTmp.length()) {
28                 maxLen = maxStrTmp.length();
29                 maxStr = maxStrTmp;
30             }
31         }
32         return maxStr;
33     }
34 
35     private static int getMaxPossibleLength(int index, int length) {
36         int head = 0;
37         int tail = length - 1;
38         if (index == head || index == tail) {
39             return 1;
40         }
41         int result1 = index - head;
42         int result2 = tail - index;
43 
44         int min = result1 <= result2 ? result1 : result2;
45         return min * 2 + 1;
46     }
47 
48     private static String getMaxStrByIndex(int index, char[] chars) {
49         StringBuilder sb = new StringBuilder(String.valueOf(chars[index]));
50         int length = chars.length;
51         int head = index - 1;
52         int tail = index + 1;
53 
54         // middle deal
55         while (true) {
56             if (head >= 0 && chars[index] == chars[head]) {
57                 sb.insert(0, String.valueOf(chars[head--]));
58             } else if (tail <= length - 1 && chars[index] == chars[tail]) {
59                 sb.append(String.valueOf(chars[tail++]));
60             } else {
61                 break;
62             }
63         }
64 
65         // besides deal
66         while (true) {
67             if (head < 0 || tail > length - 1) {
68                 break;
69             }
70             if (head >= 0 && tail <= length - 1 && chars[head] == chars[tail]) {
71                 sb.insert(0, String.valueOf(chars[head--]));
72                 sb.append(String.valueOf(chars[tail++]));
73                 continue;
74             }
75             break;
76 
77         }
78         return sb.toString();
79     }
80 }
View Code

  

2. dp解法

思路: 设 p[i][j] 代表下标从i至j的子字符串是否是回文串,取值为boolean

转移方程 p[i][j] = p[i+1][j-1] && chars[i] == chars[j]

初始化的状态为 p[i][i] = true    p[i][i+1] = chars[i] == chars[i+1]

看下面手绘图理解一下,打勾的对角线p[i][i] 恒为true, 只有这一列是不够状态转移的,因为按照转移方程,必须要图示的↗️方向递推,那么要需要有圆圈的一列初始化,这列对应的是p[i][i+1]。 剩下的递推即可,比如图中的箭头栗子?,p[0][2]要根据p[1][1]加上元素值推演过来,而p[0][4]需要p[1][3]的值推演过来。所以更新下表的顺序是打勾列向↗️更新

public class Test1218 {

    public static void main(String[] args) {
        String str = "abcba";
        System.out.println(longestPalindrome(str));
    }

    public static String longestPalindrome(String str) {

        char[] chars = str.toCharArray();
        int length = chars.length;

        boolean dp[][] = new boolean[1002][1002];

        // 初始化间距为1的值
        int maxLen = 1;
        String maxStr = str.substring(0, 1);
        for (int i = 0; i < length; i++) {
            dp[i][i] = true;
        }

        // 初始化间距为2的值
        for (int i = 0; i < length - 1; i++) {
            dp[i][i + 1] = (chars[i] == chars[i + 1]);
            if (dp[i][i + 1]) {
                maxLen = 2;
                maxStr = str.substring(i, i + 2);
            }
        }

        // 状态转移
        for (int minus = 2; minus < length; minus++) {
            for (int i = 0; i < length; i++) {
                int j = minus + i;
                if (j > length - 1) {
                    break;
                }
                dp[i][j] = dp[i + 1][j - 1] && chars[i] == chars[j];
                // 回文串且长度大于之前的最大长度,进行更新
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    maxStr = str.substring(i, j + 1);
                }
            }
        }
        return maxStr;
    }
}
View Code

 

 

 

二 最大盛水量/面积(第11题)

1. 我的解法(tle): 暴力遍历,剪枝掉低于两端的"局部较低的数据"

 1 public class Test1218 {
 2     public static void main(String[] args) {
 3         int i = maxArea(new int[]{1, 3, 2, 1, 5});
 4         System.out.println(i);
 5     }
 6 
 7     public static int maxArea(int[] height) {
 8 
 9         int length = height.length;
10         int[] leftMaxArray = new int[length];
11         int leftMax = 0;
12         for (int i = 0; i < length; i++) {
13             leftMax = height[i] > leftMax ? height[i] : leftMax;
14             leftMaxArray[i] = leftMax;
15         }
16 
17         int[] rightMaxArray = new int[length];
18         int rightMax = 0;
19         for (int i = length - 1; i >= 0; i--) {
20             rightMax = height[i] > rightMax ? height[i] : rightMax;
21             rightMaxArray[i] = rightMax;
22         }
23 
24 
25         // 减枝
26         boolean[] flag = new boolean[length];
27         flag[0] = true;
28         flag[length - 1] = true;
29         for (int i = 1; i < length - 1; i++) {
30             flag[i] = !(height[i] < leftMaxArray[i - 1] && height[i] < rightMaxArray[i + 1]);
31         }
32 
33         int max = 0;
34         for (int i = 0; i < length; i++) {
35             for (int j = i + 1; j < length; j++) {
36                 if (!flag[j]) {
37                     continue;
38                 }
39                 int minH = height[i] > height[j] ? height[j] : height[i];
40                 int tmpArea = (j - i) * minH;
41                 if (tmpArea > max) {
42                     max = tmpArea;
43                 }
44             }
45         }
46         return max;
47     }
48 }
View Code

2. 贪心

两个指针l和r,初始化为数组的两端,然后向中间移动找到最大的面积。如果l指向的数字小,则l需要右移才有可能获得更大容量,因为r左移,得到的容量肯定比r左移之前的容量小(高度已经被较小的l限制住了)。同理,r指向的数据小的话,则需要进行左移r。

时间复杂度:O(n)

空间复杂度:O(1)

 1 public class Test1218 {
 2     public static void main(String[] args) {
 3         int i = maxArea(new int[]{1, 3, 2, 1, 5});
 4         System.out.println(i);
 5     }
 6 
 7     public static int maxArea(int[] height) {
 8         int left = 0;
 9         int right = height.length - 1;
10         int maxArea = 0;
11         while (left < right) {
12             maxArea = Math.max(maxArea, (right - left) * Math.min(height[left], height[right]));
13             if (height[left] < height[right]) {
14                 left++;
15             } else {
16                 right--;
17             }
18         }
19         return maxArea;
20     }
21 }
View Code

 

 

 

三 判断是否为回文的整数(第9题)

Determine whether an integer is a palindrome. Do this without extra space.

1. 我的解法(accepted, 不过不是最优空间复杂度,和题意零额外空间不符): 换成char[], 遍历一半

 1 class Solution {
 2     public static void main(String[] args) {
 3         boolean palindrome = isPalindrome(-121);
 4         System.out.println(palindrome);
 5     }
 6 
 7     public static boolean isPalindrome(int x) {
 8         if (x < 0) {
 9             x = -x;
10         }
11         char[] charArray = String.valueOf(x).toCharArray();
12         int length = charArray.length;
13         for (int i = 0; i < length >> 1; i++) {
14             if (charArray[i] == charArray[length - 1 - i]) {
15                 return true;
16             }
17         }
18         return false;
19     }
20 }
View Code

 

2. 按位除法&取余处理,构造出逆序的字串进行比较

 1 public class Test1218 {
 2     public static void main(String[] args) {
 3         boolean palindrome = isPalindrome(-2147447412);
 4         System.out.println(palindrome);
 5     }
 6 
 7     public static boolean isPalindrome(int x) {
 8         if (x < 0 || (x % 10 == 0 && x != 0)) {
 9             return false;
10         }
11 
12         int revertedNumber = 0;
13         while (x > revertedNumber) {
14             revertedNumber = revertedNumber * 10 + x % 10;
15             x /= 10;
16         }
17 
18         return x == revertedNumber || x == revertedNumber / 10;
19     }
20 }
View Code

 




四 两个有序单链表合并成一个有序链表(第21题)

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

Example:

Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4

1. 我的解法(accepted): 按位置比较插入新链表

Time complexity : O(n + m)

Space complexity : O(1)

 1 class ListNode {
 2     int val;
 3     ListNode next;
 4 
 5     ListNode(int x) {
 6         val = x;
 7     }
 8 }
 9 
10 public class Test1218 {
11     public static void main(String[] args) {
12 
13         ListNode node11 = new ListNode(1);
14         ListNode node12 = new ListNode(2);
15         ListNode node13 = new ListNode(4);
16         node11.next = node12;
17         node12.next = node13;
18 
19         ListNode n1 = node11;
20 
21         ListNode node21 = new ListNode(1);
22         ListNode node22 = new ListNode(3);
23         ListNode node23 = new ListNode(4);
24         node21.next = node22;
25         node22.next = node23;
26 
27         ListNode n2 = node21;
28 
29         ListNode listNode = mergeTwoLists(n1, n2);
30         while (listNode != null) {
31             System.out.println(listNode.val);
32             listNode = listNode.next;
33         }
34     }
35 
36     public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
37         ListNode head = new ListNode(-1);
38         ListNode cur = head;
39 
40         while (l1 != null & l2 != null) {
41             if (l1.val < l2.val) {
42                 cur.next = l1;
43                 l1 = l1.next;
44             } else {
45                 cur.next = l2;
46                 l2 = l2.next;
47             }
48             cur = cur.next;
49         }
50 
51         cur.next = l1 == null ? l2 : l1;
52         return head.next;
53     }
54 }
View Code

 

2. 递归: 

灰常简约和易于书写,不过有递归的栈空间消耗

Time complexity : O(n + m)

Space complexity : O(n + m)

 1 class ListNode {
 2     int val;
 3     ListNode next;
 4 
 5     ListNode(int x) {
 6         val = x;
 7     }
 8 }
 9 
10 public class Test1218 {
11     public static void main(String[] args) {
12 
13         ListNode node11 = new ListNode(1);
14         ListNode node12 = new ListNode(2);
15         ListNode node13 = new ListNode(4);
16         node11.next = node12;
17         node12.next = node13;
18 
19         ListNode n1 = node11;
20 
21         ListNode node21 = new ListNode(1);
22         ListNode node22 = new ListNode(3);
23         ListNode node23 = new ListNode(4);
24         node21.next = node22;
25         node22.next = node23;
26 
27         ListNode n2 = node21;
28 
29         ListNode listNode = mergeTwoLists(n1, n2);
30         while (listNode != null) {
31             System.out.println(listNode.val);
32             listNode = listNode.next;
33         }
34     }
35 
36     public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
37         if (l1 == null) {
38             return l2;
39         }
40         if (l2 == null) {
41             return l1;
42         }
43         if (l1.val < l2.val) {
44             l1.next = mergeTwoLists(l1.next, l2);
45             return l1;
46         } else {
47             l2.next = mergeTwoLists(l1, l2.next);
48             return l2;
49         }
50     }
51 }
View Code

 

 

五 找出数组中三个数相加为0的不同组合(第15题)

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note: The solution set must not contain duplicate triplets.

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

1. 我的解法(Time Limit Exceeded): 两重循环i, j得到 num[i] num[j] 找到-(num[i] + num[j]), 把这三个数的集合列表进行去重,时间复杂度逼近O(n^3)

 1 public class Solution {
 2     public static void main(String[] args) {
 3 //        List<List<Integer>> lists = threeSum(new int[]{-1, 0, 1, 2, -1, -4});
 4         List<List<Integer>> lists = threeSum(new int[]{-1, 0, 1, 2, -1, -4});
 5 
 6         System.out.println(lists);
 7     }
 8 
 9     public static List<List<Integer>> threeSum(int[] nums) {
10 
11         HashSet<Integer> hashSet = new HashSet<>();
12         for (int num : nums) {
13             hashSet.add(-num);
14         }
15 
16         List<List<Integer>> duplicatedRet = new ArrayList<>();
17         List<Integer> list;
18         int length = nums.length;
19         for (int i = 0; i < length; i++) {
20             for (int j = i + 1; j < length; j++) {
21                 list = new ArrayList<>();
22                 if (hashSet.contains(nums[i] + nums[j])) {
23                     int ele[] = new int[]{nums[i], nums[j], -nums[i] - nums[j]};
24                     if (isIntList(nums, nums[i], nums[j], -nums[i] - nums[j])) {
25                         Arrays.sort(ele);
26                         for (int e : ele) {
27                             list.add(e);
28                         }
29                         duplicatedRet.add(list);
30                     }
31                 }
32             }
33         }
34 
35         List<List<Integer>> ret = new ArrayList<>();
36         for (int i = 0; i < duplicatedRet.size(); i++) {
37             boolean flag = false;
38             for (int j = i + 1; j < duplicatedRet.size(); j++) {
39                 if (ifSame(duplicatedRet.get(i), duplicatedRet.get(j))) {
40                     flag = true;
41                     break;
42                 }
43             }
44             if (!flag) {
45                 ret.add(duplicatedRet.get(i));
46             }
47         }
48         return ret;
49     }
50 
51     private static boolean isIntList(int[] nums, int n1, int n2, int n3) {
52         List<Integer> list = new ArrayList<>();
53         for (int i : nums) {
54             list.add(i);
55         }
56         return list.remove((Integer) n1) && list.remove((Integer) n2) && list.remove((Integer) n3);
57     }
58 
59     private static boolean ifSame(List<Integer> l1, List<Integer> l2) {
60         return Objects.equals(l1.get(0), l2.get(0)) && Objects.equals(l1.get(1), l2.get(1)) && Objects.equals(l1.get(2), l2.get(2));
61     }
62 }
View Code

 

2. 排序,遍历每个数i时,看是否后面的两个数可以相加等于-i, 双端遍历,合理剪枝,比如相同的数字略过,遍历到倒数第三个,遍历后期的数为正直接break等

 1 import java.util.*;
 2 class Solution {
 3   public static void main(String[] args) {
 4         List<List<Integer>> lists = threeSum(new int[]{-1, 0, 1, 2, -1, -4});
 5         System.out.println(lists);
 6     }
 7 
 8     public static List<List<Integer>> threeSum(int[] nums) {
 9         List<List<Integer>> ret = new ArrayList<>();
10         int length = nums.length;
11         Arrays.sort(nums);
12         for (int i = 0; i < length - 2; i++) {
13             // 剪枝。已排序,整数作为最小的数,无法构造出三个数相加等于0
14             if (nums[i] > 0) {
15                 break;
16             }
17 
18             // 剪枝。相等的数无需重复计算
19             if (i > 0 && nums[i] == nums[i - 1]) {
20                 continue;
21             }
22 
23             int target = -nums[i];
24             int left = i + 1;
25             int right = length - 1;
26 
27             while (left < right) {
28                 if (target == nums[left] + nums[right]) {
29                     ret.add(Arrays.asList(nums[i], nums[left], nums[right]));
30                     // 去重
31                     while (left < right && nums[left] == nums[left + 1]) {
32                         left++;
33                     }
34                     while (left < right && nums[right] == nums[right - 1]) {
35                         right--;
36                     }
37                     left++;
38                     right--;
39                 } else if (target > nums[left] + nums[right]) {
40                     left++;
41                 } else {
42                     right--;
43                 }
44             }
45         }
46         return ret;
47     }
48 }
View Code

 

 

 

六 top K问题(第347题)

m个数找出出现频率最大的k个

1. 桶排序解法,比如a出现3次, b出现6次,c出现3次,那么构造出bucket[3] = Arrays.asList(a, c), bucket[6] = Arrays.asList(b)

public class TTest {
    public static void main(String[] args) {
//        List<Integer> integers = topKFrequent(new int[]{4, 6, 6, 3, 3, 3, 3}, 2);
//        List<Integer> integers = topKFrequent(new int[]{1, 1, 1, 2, 2, 2, 3, 3, 3}, 2);
//        List<Integer> integers = topKFrequent(new int[]{3, 0, 1, 0}, 2);
        List<Integer> integers = topKFrequent2(new int[]{1}, 1);
        System.out.println(integers);
    }

    /**
     * 桶排序
     */
    public static List<Integer> topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> map = new LinkedHashMap<>();
        List<Integer>[] bucket = new List[nums.length];
        List<Integer> res = new ArrayList<>();
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
        for (int key : map.keySet()) {
            int frequency = map.get(key);
            if (bucket[frequency] == null) {
                bucket[frequency] = new ArrayList<>();
            }
            bucket[frequency].add(key);
        }
        for (int pos = bucket.length - 1; pos >= 0; pos--) {
            if (bucket[pos] != null) {
                for (int i = 0; i < bucket[pos].size() && res.size() < k; i++)
                    res.add(bucket[pos].get(i));
            }
        }
        return res;
    }
}
View Code

 

1. 堆排序解法,用集合中的PriorityQueue

    /**
     * 堆排序原理,优先队列
     */
    public static List<Integer> topKFrequent2(int[] nums, int k) {
        Map<Integer, Integer> map = new LinkedHashMap<>();
        for (int n : nums) {
            map.put(n, map.getOrDefault(n, 0) + 1);
        }

        PriorityQueue<Map.Entry<Integer, Integer>> heap = new PriorityQueue<>((l, r) -> r.getValue() - l.getValue());
        heap.addAll(map.entrySet());

        List<Integer> res = new ArrayList<>();
        while (res.size() < k) {
            res.add(heap.poll().getKey());
        }
        return res;
    }
View Code

 

 

七 二叉树左右对称(第101题)

返回是否一个二叉树为左右对称结构

1. 我的解法(accepted): 比较中序和先序是否完全相等

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        List<Integer> list1 = new ArrayList();
        inOrder(root, list1);
        
        List<Integer> list2 = new ArrayList();
        inOrder1(root, list2);
        
        List<Integer> list3 = new ArrayList();
        preOrder(root, list3);
        
        List<Integer> list4 = new ArrayList();
        preOrder1(root, list4);
        
        return isSame(list1, list2) && isSame(list3, list4);
    
    }
    
    private boolean isSame(List<Integer> list1, List<Integer> list2) {
        if (list1.size() != list2.size()) {
            return false;
        }
        
        for (int i = 0; i < list1.size(); i++) {
            if (list1.get(i) != list2.get(i)) {
                return false;
            }
        }
        return true;
    }
    
    private void inOrder(TreeNode root, List<Integer> numList) {
        if (root == null) {
            return;
        }
        inOrder(root.left, numList);
        numList.add(root.val);
        inOrder(root.right, numList);
    }
    
    private void inOrder1(TreeNode root, List<Integer> numList) {
        if (root == null) {
            return;
        }
        inOrder1(root.right, numList);
        numList.add(root.val);
        inOrder1(root.left, numList);
    }
    
    private void preOrder(TreeNode root, List<Integer> numList) {
        if (root == null) {
            return;
        }
        numList.add(root.val);
        preOrder(root.left, numList);
        preOrder(root.right, numList);
    }
    
    private void preOrder1(TreeNode root, List<Integer> numList) {
        if (root == null) {
            return;
        }
        numList.add(root.val);
        preOrder1(root.right, numList);
        preOrder1(root.left, numList);
    }
}
View Code

2. 递归

public boolean isSymmetric(TreeNode root) {
    return isMirror(root, root);
}

public boolean isMirror(TreeNode t1, TreeNode t2) {
    if (t1 == null && t2 == null) return true;
    if (t1 == null || t2 == null) return false;
    return (t1.val == t2.val)
        && isMirror(t1.right, t2.left)
        && isMirror(t1.left, t2.right);
}
View Code

3. 非递归

public boolean isSymmetric(TreeNode root) {
    Queue<TreeNode> q = new LinkedList<>();
    q.add(root);
    q.add(root);
    while (!q.isEmpty()) {
        TreeNode t1 = q.poll();
        TreeNode t2 = q.poll();
        if (t1 == null && t2 == null) continue;
        if (t1 == null || t2 == null) return false;
        if (t1.val != t2.val) return false;
        q.add(t1.left);
        q.add(t2.right);
        q.add(t1.right);
        q.add(t2.left);
    }
    return true;
}
View Code

 

转载于:https://www.cnblogs.com/balfish/p/8137229.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值