leetcode 1

无重复字符的最长字串

给定一个字符串 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/

给定两个大小分别为 mn 的正序(从小到大)数组 nums1nums2。请你找出并返回这两个正序数组的 中位数

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个子数组的最大和,为了得到下标,进行回溯。

递推公式:

image-20211208150809965

两外一种思路,活动窗口:

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值