最長無重複子陣列
給定一個陣列arr,返回arr的最長無重複元素子陣列的長度,無重複指的是所有數字都不相同。子陣列是連續的,比如[1,3,5,7,9]的子陣列有[1,3],[3,5,7]等等,但是[1,3,7]不是子陣列
輸入:
[1,2,3,1,2,3,2,2]
返回值:
3
複製
說明:
最長子陣列為[1,2,3]
方法一:
public class Solution {
/**
*
* @param arr int整型一維陣列 the array
* @return int整型
*/
public int maxLength (int[] arr) {
if(arr.length <= 1) {
return arr.length;
}
// 無重複的起點
int a = 0;
// 當前無重複的最大長度
int max = 1;
// 1,2,3,1,4
for(int b = 1; b < arr.length;b++) {
// 尋找[a, b-1]是否存在於arr[b]相等的數, 如果存在則要更新a的值
for(int i = b-1; i >= a; i--) {
if(arr[i] == arr[b]) {
a = i + 1;
break;
}
}
max = Math.max(max, b - a + 1);
}
return max;
}
}
方法二:
public class Solution {
/**
*
* @param arr int整型一維陣列 the array
* @return int整型
*/
public int maxLength (int[] arr) {
if(arr.length <= 1) {
return arr.length;
}
// 無重複的起點
int a = 0;
// 當前無重複的最大長度
int max = 0;
// 使用一個Map來儲存已經遍歷過的元素
Map<Integer, Integer> map = new HashMap();
// 1,2,3,1,4
for(int b = 0; b < arr.length;b++) {
if(map.containsKey(arr[b])) {
// 每次的取值都要大於等於a, 防止a往前走
a = Math.max(a, map.get(arr[b]) + 1);
}
map.put(arr[b], b);
max = Math.max(max, b - a + 1);
}
return max;
}
}
方法三:
public class Solution {
/**
*
* @param arr int整型一維陣列 the array
* @return int整型
*/
public int maxLength (int[] arr) {
if(arr.length <= 1) {
return arr.length;
}
int max = 0;
// 使用一個佇列來儲存當前無重複的資料
LinkedList<Integer> queue = new LinkedList();
for(int i = 0; i < arr.length; i++) {
// 遇到重複元素時,從頭部一直出棧,知道無重複元素
while(queue.contains(arr[i])) {
queue.removeFirst();
}
queue.addLast(arr[i]);
max = Math.max(max, queue.size());
}
return max;
}
}
子陣列的最大累加和問題
給定一個陣列arr,返回子陣列的最大累加和
例如,arr = [1, -2, 3, 5, -2, 6, -1],所有子陣列中,[3, 5, -2, 6]可以累加出最大的和12,所以返回12.
題目保證沒有全為負數的資料
[要求]
時間複雜度為O(n),空間複雜度為O(1)
輸入:
[1, -2, 3, 5, -2, 6, -1]
返回值:
12
方法一:空間複雜度為O(n)
public class Solution {
/**
*
* 狀態轉移方程如下
* dp[0] = arr[0];
* dp[i - 1] > 0 ==> dp[i] = dp[i - 1] + arr[i];
* dp[i - 1] <= 0 ==> dp[i] = arr[i];
*/
public int maxsumofSubarray (int[] arr) {
if(arr.length == 0) {
return 0;
}
if(arr.length == 1) {
return arr[0];
}
int[] dp = new int[arr.length];
dp[0] = arr[0];
int max = dp[0];
for(int i = 1; i < arr.length; i++) {
if(dp[i - 1] > 0) {
dp[i] = dp[i - 1] + arr[i];
} else {
dp[i] = arr[i];
}
max = Math.max(max, dp[i]);
}
return max;
}
}
方法二:空間複雜度為O(1)
public class Solution {
/**
* 狀態轉移方程如下
* dp[0] = arr[0];
* dp[i - 1] > 0 ==> dp[i] = dp[i - 1] + arr[i];
* dp[i - 1] <= 0 ==> dp[i] = arr[i];
*/
public int maxsumofSubarray (int[] arr) {
if(arr.length == 0) {
return 0;
}
if(arr.length == 1) {
return arr[0];
}
int pre = arr[0];
int max = pre;
for(int i = 1; i < arr.length; i++) {
if(pre > 0) {
pre = pre + arr[i];
} else {
pre = arr[i];
}
max = Math.max(max, pre);
}
return max;
}
}
刪除有序連結串列中重複的元素-II
給出一個升序排序的連結串列,刪除連結串列中的所有重複出現的元素,只保留原連結串列中只出現一次的元素。
例如:
給出的連結串列為1→2→3→3→4→4→5, 返回1→2→5.
給出的連結串列為1→1→1→2→3, 返回2→3.
方法一:空間複雜度O(n)
過程:
public class Solution {
/**
*
* @param head ListNode類
* @return ListNode類
*/
public ListNode deleteDuplicates (ListNode head) {
// 設定一個偽節點,主要是為了方便處理
ListNode result = new ListNode(0);
ListNode resultTemp = result;
ListNode h = head;
while(h != null) {
ListNode cur = h;
ListNode node = cur.next;
boolean flag = false;
// 這裡是為了找到當前節點是否存在重複元素
while(node != null) {
if(node.val == cur.val) {
flag = true;
// 這裡主要是過濾掉重複的
node = node.next;
} else {
break;
}
}
if(!flag) {
// 不存在重複元素,則新建一個元素
resultTemp.next = new ListNode(cur.val);
resultTemp = resultTemp.next;
}
// h指向node: 因為此時的node是指向一個與cur不相等的節點, 如果h直接指向node就行了
h = node;
}
return result.next;
}
}
方法二:空間複雜度O(1),直接在原連結串列上面操作
public class Solution {
/**
*
* @param head ListNode類
* @return ListNode類
*/
public ListNode deleteDuplicates (ListNode head) {
// 設定一個偽節點,主要是為了方便處理
ListNode result = new ListNode(0);
result.next = head;
// 前指標
ListNode pre = result;
// 當前指標
ListNode cur = head;
// 每次都判斷當前指標的下一個指標是否與當前指標的值相同
// 如果相同, 則找到第一個與當前指標不相同的節點node, 然後將前指標的next指標指向node
// 如果不相同, 則前指標和當前指標都指向下一個
// 1 2 3 3 4 4 5
while(cur != null) {
if(cur.next != null && cur.next.val == cur.val) {
// 存在相同值
ListNode node = cur.next;
// 這裡主要是讓node指向一個不與cur相同的節點
while(node != null && node.val == cur.val) {
node = node.next;
}
// 直接將 pre.next 指向 node, 達到了刪除相同元素的目的
pre.next = node;
cur = node;
} else {
// 不存在相同值, 都指向下一個指標
pre = pre.next;
cur = cur.next;
}
}
return result.next;
}
}
最長迴文子串
對於一個字串,請設計一個高效演算法,計算其中最長迴文子串的長度。
給定字串A以及它的長度n,請返回最長迴文子串的長度。
輸入:"abc1234321ab",12
返回:7
方法一: 暴力法
public class Solution {
public int getLongestPalindrome(String A, int n) {
// write code here
if(n <= 1) {
return n;
}
int max = 1;
char[] chars = A.toCharArray();
// 兩個for迴圈遍歷所有可能的子串
for(int i = 0; i < n; i++) {
for(int j = i + 1; j < n; j++) {
// 如果當前字串長度大於 max 並且是迴文
if(j - i + 1 > max && isHuiwen(chars, i, j)) {
max = j - i + 1;
}
}
}
return max;
}
public boolean isHuiwen(char[] chars, int i, int j) {
while(i < j) {
if(chars[i] != chars[j]) {
return false;
}
i++;
j--;
}
return true;
}
}
方法二: 動態規劃
dp[left][right]代表[left, right]之間是否為迴文
s.charAt(left) == s.charAt(right)
如果 right - left <= 2, dp[left][right] = true; 則字元長度為2或者3, 類似於這種: "aa"、"aba"
如果 right - left > 2, dp[left][right] = dp[left+1][right-1];
public class Solution {
public int getLongestPalindrome(String A, int n) {
if(n < 2) {
return A.length();
}
boolean[][] dp = new boolean[n][n];
int max = 1;
char[] chars = A.toCharArray();
for(int right = 1; right < n; right++) {
for(int left = 0; left < right; left++) {
// 如果不相同, 說明[left, right]肯定不是迴文
if(chars[left] != chars[right]) {
continue;
}
if(right - left <= 2){
// aa 或者 aba
dp[left][right] = true;
} else {
dp[left][right] = dp[left + 1][right - 1];
}
if(dp[left][right]) {
max = Math.max(max, right - left + 1);
}
}
}
return max;
}
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結