无重复字符的最长字串
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
class Solution {
public int lengthOfLongestSubstring(String s) {
int ans = 0, n = s.length();
Map<Character, Integer> map = new HashMap<>();
for(int i = 0, j = 0; j < n; j++) {
char c = s.charAt(j);
if(map.containsKey(c)) {
i = Math.max(map.get(c), i);
}
ans = Math.max(j-i+1, ans);
map.put(c, j+1);
}
return ans;
}
}
使用Hash记录无重复的最后一个位置
正序数组中位数
https://leetcode-cn.com/problems/median-of-two-sorted-arrays/
给定两个大小分别为 m
和 n
的正序(从小到大)数组 nums1
和 nums2
。请你找出并返回这两个正序数组的 中位数 。
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length;
int loc = (m+n)/2;
int[] s = new int[m+n];
int i = 0, j = 0, h = 0;
while(i < m && j < n) {
if(nums1[i] < nums2[j]){
s[h++] = nums1[i++];
}
else s[h++] = nums2[j++];
}
if(i < m) {
for(int k = i; k < m; k++){
s[h++] = nums1[k];
}
}else {
for(int k = j; k < n; k++){
s[h++] = nums2[k];
}
}
if((m+n) % 2 == 0) {
return (s[loc-1]+s[loc])*1.0 / 2;
}else return s[loc]*1.0;
}
}
log(M+N)做法:
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int length1 = nums1.length, length2 = nums2.length;
int totalLength = length1 + length2;
if (totalLength % 2 == 1) {
int midIndex = totalLength / 2;
double median = getKthElement(nums1, nums2, midIndex + 1);
return median;
} else {
int midIndex1 = totalLength / 2 - 1, midIndex2 = totalLength / 2;
double median = (getKthElement(nums1, nums2, midIndex1 + 1) + getKthElement(nums1, nums2, midIndex2 + 1)) / 2.0;
return median;
}
}
int getKthElement(int[] nums1, int[] nums2, int k) {
int length1 = nums1.length, length2 = nums2.length;
int index1 = 0, index2 = 0;
int kthElement = 0;
while(true) {
if(index1 == length1) {
return nums2[index2 + k-1];
}
if(index2 == length2) {
return nums1[index1 + k - 1];
}
if(k == 1) {
return Math.min(nums1[index1], nums2[index2]);
}
int nindex1 = Math.min(length1, index1 + k/2) -1;
int nindex2 = Math.min(length2, index2 + k/2) -1;
int p1 = nums1[nindex1], p2 = nums2[nindex2];
if(p1 < p2) {
k -= (nindex1 - index1 + 1);
index1 = nindex1 + 1;
}else {
k -= (nindex2 - index2 + 1);
index2 = nindex2 + 1;
}
}
}
}
最长回文子串
根据回文串的定义,正着和反着读一样,把原来的字符串倒置了,然后找最长的公共子串就可以了。例如 S = “caba” ,S = “abac”,最长公共子串是 “aba”,所以原字符串的最长回文串就是 “aba”。
关于求最长公共子串用DP
public String longestPalindrome(String s) {
if (s.equals(""))
return "";
String origin = s;
String reverse = new StringBuffer(s).reverse().toString(); //字符串倒置
int length = s.length();
int[][] arr = new int[length][length];
int maxLen = 0;
int maxEnd = 0;
for (int i = 0; i < length; i++)
for (int j = 0; j < length; j++) {
if (origin.charAt(i) == reverse.charAt(j)) {
if (i == 0 || j == 0) {
arr[i][j] = 1;
} else {
arr[i][j] = arr[i - 1][j - 1] + 1;
}
}
// if (arr[i][j] > maxLen) {
// maxLen = arr[i][j];
// maxEnd = i; //以 i 位置结尾的字符
// }
if (arr[i][j] > maxLen) {
int beforeRev = length - 1 - j;
if (beforeRev + arr[i][j] - 1 == i) { //判断下标是否对应
maxLen = arr[i][j];
maxEnd = i;
}
}
}
return s.substring(maxEnd - maxLen + 1, maxEnd + 1);
}
记得判断反转之前的位置和之后的位置的一致性
优化空间,改变j的计算方向,时间复杂度降维
class Solution {
public String longestPalindrome(String s) {
if (s.equals(""))
return "";
String origin = s;
String reverse = new StringBuffer(s).reverse().toString();
int length = s.length();
int[] arr = new int[length];
int maxLen = 0;
int maxEnd = 0;
for (int i = 0; i < length; i++)
for (int j = length - 1; j >= 0; j--) {
if (origin.charAt(i) == reverse.charAt(j)) {
if (i == 0 || j == 0) {
arr[j] = 1;
} else {
arr[j] = arr[j - 1] + 1;
}
}
else {
arr[j] = 0;
}
/**********修改的地方*******************/
if (arr[j] > maxLen) {
int beforeRev = length - 1 - j;
if (beforeRev + arr[j] - 1 == i) { //判断下标是否对应
maxLen = arr[j];
maxEnd = i;
}
/*************************************/
}
}
return s.substring(maxEnd - maxLen + 1, maxEnd + 1);
}
}
三个无重叠子数组的最大和
给你一个整数数组 nums
和一个整数 k
,找出三个长度为 k
、互不重叠、且 3 * k
项的和最大的子数组,并返回这三个子数组。
以下标的数组形式返回结果,数组中的每一项分别指示每个子数组的起始位置(下标从 0 开始)。如果有多个结果,返回字典序最小的一个。
class Solution {
public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
int n = nums.length;
int[] sum = new int[n+1];
for(int i = 1; i <= n; i++) {
sum[i] = sum[i-1] + nums[i-1];
}
int[][] f = new int[n+10][4];
for(int i = n-k+1; i>=1; i--) {
for(int j = 1; j < 4; j++) {
f[i][j] = Math.max(f[i+1][j], f[i+k][j-1] + sum[i+k-1]-sum[i-1]);
}
}
int[] res = new int[3];
int i = 1, j = 3;
int idx = 0;
while(j > 0) {
if(f[i+1][j] > f[i+k][j-1] + sum[i+k-1]-sum[i-1]) {
i++;
}else {
res[idx++] = i-1;
i+=k;
j--;
}
}
return res;
}
}
定义f [i] [j] 为前i个数字分为j个子数组的最大和,为了得到下标,进行回溯。
递推公式:
两外一种思路,活动窗口:
class Solution {
public int[] maxSumOfThreeSubarrays(int[] nums, int k) {
int[] ans = new int[3];
int sum1 = 0, maxSum1 = 0, maxSum1Idx = 0;
int sum2 = 0, maxSum12 = 0, maxSum12Idx1 = 0, maxSum12Idx2 = 0;
int sum3 = 0, maxTotal = 0;
for (int i = k * 2; i < nums.length; ++i) {
sum1 += nums[i - k * 2];
sum2 += nums[i - k];
sum3 += nums[i];
if (i >= k * 3 - 1) {
if (sum1 > maxSum1) {
maxSum1 = sum1;
maxSum1Idx = i - k * 3 + 1;
}
if (maxSum1 + sum2 > maxSum12) {
maxSum12 = maxSum1 + sum2;
maxSum12Idx1 = maxSum1Idx;
maxSum12Idx2 = i - k * 2 + 1;
}
if (maxSum12 + sum3 > maxTotal) {
maxTotal = maxSum12 + sum3;
ans[0] = maxSum12Idx1;
ans[1] = maxSum12Idx2;
ans[2] = i - k + 1;
}
sum1 -= nums[i - k * 3 + 1];
sum2 -= nums[i - k * 2 + 1];
sum3 -= nums[i - k + 1];
}
}
return ans;
}
}
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/maximum-sum-of-3-non-overlapping-subarrays/solution/san-ge-wu-zhong-die-zi-shu-zu-de-zui-da-4a8lb/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
电话号码的字母组合
回溯
class Solution {
private static final String[] KEYS = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
public List<String> letterCombinations(String digits) {
List<String> com = new ArrayList<>();
combinations(new StringBuilder(), digits, com);
return com;
}
public void combinations(StringBuilder prefix, String digits, List<String> com) {
if(prefix.length() == digits.length()) {
com.add(prefix.toString());
return;
}
int cur = digits.charAt(prefix.length()) - '0';
for(char c : KEYS[cur].toCharArray()) {
prefix.append(c);
combinations(prefix, digits, com);
prefix.deleteCharAt(prefix.length() - 1);
}
}
}
保持天际线
给你一座由 n x n 个街区组成的城市,每个街区都包含一座立方体建筑。给你一个下标从 0 开始的 n x n 整数矩阵 grid ,其中 grid[r][c] 表示坐落于 r 行 c 列的建筑物的 高度 。
城市的 天际线 是从远处观察城市时,所有建筑物形成的外部轮廓。从东、南、西、北四个主要方向观测到的 天际线 可能不同。
我们被允许为 任意数量的建筑物 的高度增加 任意增量(不同建筑物的增量可能不同) 。 高度为 0 的建筑物的高度也可以增加。然而,增加的建筑物高度 不能影响 从任何主要方向观察城市得到的 天际线 。
在 不改变 从任何主要方向观测到的城市 天际线 的前提下,返回建筑物可以增加的 最大高度增量总和 。
求出行列的最大值,然后对每个元素循环。
class Solution {
public int maxIncreaseKeepingSkyline(int[][] grid) {
int n = grid.length;
int[] top1 = new int[n];
int[] top2 = new int[n];
int temp = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
if(grid[i][j] > top1[i]) {
top1[i] = grid[i][j];
}
if(grid[j][i] > top2[i]) {
top2[i] = grid[j][i];
}
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
int h = Math.min(top1[i], top2[j]);
temp += h-grid[i][j];
}
}
return temp;
}
}
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isEvenOddTree(TreeNode root) {
Queue<TreeNode> queue = new ArrayDeque<TreeNode>();
queue.offer(root);
int level = 0;
while(!queue.isEmpty()) {
int size = queue.size();
int prev = level % 2 == 0 ? Integer.MIN_VALUE : Integer.MAX_VALUE;
for(int i = 0; i < size; i++) {
TreeNode node = queue.poll();
int val = node.val;
if(level % 2 == val % 2) {
return false;
}
if((level % 2 == 0 && val <= prev) || (level % 2 != 0 && val >= prev)) {
return false;
}
if(node.left != null) {
queue.offer(node.left);
}
if(node.right != null) {
queue.offer(node.right);
}
prev = val;
}
level++;
}
return true;
}
}
class Solution {
public String[] findOcurrences(String text, String first, String second) {
String[] s = text.split(" ");
int n = s.length;
List<String> ls = new ArrayList<>();
for(int i = 0; i + 2 < n; i++) {
if(s[i].equals(first) && s[i+1].equals(second)) {
ls.add(s[i+2]);
}
}
return ls.toArray(new String[ls.size()]);
}
}
手写一次KMP
class Solution {
public int repeatedStringMatch(String a, String b) {
StringBuilder sb = new StringBuilder();
int ans = 0;
while (sb.length() < b.length() && ++ans > 0) sb.append(a);
sb.append(a);
int x = index_KMP(sb.toString(), b);
if (x == -1) return -1;
return x+b.length() > ans*a.length() ? ans+1 : ans;
}
void get_next(String tt, int[] next) {
next[1] = 0;
tt = " " + tt;
int n = tt.length();
int i = 1, j = 0;
while(i < n) {
if(j == 0 || tt.charAt(i) == tt.charAt(j)) {
i++; j++;
next[i] = j;
}
else {
j = next[j];
}
}
}
int index_KMP(String ss, String tt) {
int[] next = new int[ss.length()+1];
get_next(tt, next);
tt = " " + tt;
int n = ss.length();
int m = tt.length();
int i = 0, j = 1;
while(i < n && j < m) {
if(j == 0 || ss.charAt(i) == tt.charAt(j)) {
i++; j++;
}
else {
j = next[j];
}
}
if(j == m) {
return i-m+1;
}
else return -1;
}
}
https://leetcode-cn.com/problems/repeated-string-match/
// 夜晚n位旅行者要过桥,总共只有一个手电筒,一次最多两人过桥,且过桥必须使用手电筒。每位旅行者单独过桥的所需的时间已知,两人结伴渡桥所用的时间为两人中最长的时间。
// 求解所有人过桥所用的总时间最短是多少。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int p[1100];
int cmp(int a, int b) {
return a < b;
}
int solve(int n) {
if(n == 1)
return p[0];
else if(n == 2)
return p[0] + p[1];
else if(n == 3)
return p[2] + p[1] + p[0];
if(p[1]*2>=p[0]+p[n-2])
return 2*p[0] + p[n - 1] + p[n - 2] + solve(n - 2);
else
return 2 * p[1] + p[0] + p[n - 1] + solve(n - 2);
}
int main(int argc, char const *argv[])
{
int T;
int n;
int i,j;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
memset(p,0,sizeof(p));
for(i=0;i<n;i++)
{
scanf("%d",&p[i]);
}
sort(p,p+n,cmp);
printf("%d\n",solve(n));
}
return 0;
}