输入一个正整数 target
,输出所有和为 target
的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9 输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15 输出:[[1,2,3,4,5],[4,5,6],[7,8]]
限制:
1 <= target <= 10^5
- 数学
- 双指针
- 枚举
著书三年倦写字,如今翻书不识志,若知倦书悔前程 ,无如渔樵未识时
输入一个正整数 target
,输出所有和为 target
的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9 输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15 输出:[[1,2,3,4,5],[4,5,6],[7,8]]
限制:
1 <= target <= 10^5
双指针
class Solution {
public int[][] findContinuousSequence(int target) {
int l = 1;
int r = 2;
List<int[]> res = new ArrayList<>();
while (l<r){
int sum = (l + r) * (r - l + 1) / 2;
if (sum == target){
int[] arr = new int[r - l + 1];
int tmp = l-1;
while (++tmp <=r){
arr[tmp - l] = tmp;
}
res.add(arr);
l++;
continue;
}
if (sum < target){
r++;
}else{
l++;
}
}
return res.toArray(new int[res.size()][]);
}
}
输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,则输出任意一对即可。
示例 1:
输入:nums = [2,7,11,15], target = 9 输出:[2,7] 或者 [7,2]
示例 2:
输入:nums = [10,26,30,31,47,60], target = 40 输出:[10,30] 或者 [30,10]
限制:
1 <= nums.length <= 10^5
1 <= nums[i] <= 10^6
哈希表,双指针,二分查找
boolen[]
,我试过class Solution {
public int[] twoSum(int[] nums, int target) {
boolean[] hashSet = new boolean[2000000];
for (int num : nums) {
if (hashSet[target-num]){
return new int[]{num,target-num};
}
hashSet[num] = true;
}
return new int[2];
}
}
class Solution {
public int[] twoSum(int[] nums, int target) {
int l = 0;
int r = nums.length-1;
while ( l < r){
int sum = nums[l] + nums[r];
if(sum == target){
return new int[]{nums[l],nums[r]};
}
if( sum < target){
l++;
}else{
r--;
}
}
return new int[]{nums[l],nums[r]};
}
}
class Solution {
public int[] twoSum(int[] nums, int target) {
int i = -1;
while (++i < nums.length){
int s = binarySearch(nums,target- nums[i]);
if (s >= 0 && i != s){
return new int[]{nums[i],nums[s]};
}
}
return new int[2];
}
int binarySearch(int[] nums, int t ){
int l = 0;
int r = nums.length;
while (l < r){
int mid = l + ((r-l) >> 1);
if (nums[mid] == t){
return mid;
}
if (nums[mid] > t){
r = mid;
}else{
l = mid+1;
}
}
return -1;
}
}
给你一个整数数组 nums
和一个整数 k
,按以下方法修改该数组:
i
并将 nums[i]
替换为 -nums[i]
。重复这个过程恰好 k
次。可以多次选择同一个下标 i
。
以这种方式修改数组后,返回数组 可能的最大和 。
示例 1:
输入:nums = [4,2,3], k = 1 输出:5 解释:选择下标 1 ,nums 变为 [4,-2,3] 。
示例 2:
输入:nums = [3,-1,0,2], k = 3 输出:6 解释:选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2] 。
示例 3:
输入:nums = [2,-3,-1,5,-4], k = 2 输出:13 解释:选择下标 (1, 4) ,nums 变为 [2,3,-1,5,4] 。
提示:
1 <= nums.length <= 104
-100 <= nums[i] <= 100
1 <= k <= 104
马马虎虎优先队列
class Solution {
public int largestSumAfterKNegations(int[] nums, int k) {
int sum = 0;
PriorityQueue<Integer> queue = new PriorityQueue<>();
int absMin = 101;
for (int num : nums) {
absMin = Math.min(absMin,Math.abs(num));
if (num >= 0){
sum += num;
}else{
queue.offer(num);
}
}
if (queue.size()>0){
//把绝对值较大的负数尽量翻转
while (!queue.isEmpty() && k > 0){
sum -= queue.poll();
k--;
}
if (k==0){
//翻转次数用完了,还有数字没翻转
while (!queue.isEmpty()){
sum += queue.poll();
}
return sum;
}
}
if (k%2 == 0){
return sum;
}else{
return sum - 2*absMin;
}
}
}
给你一个长度为 n
的整数数组 score
,其中 score[i]
是第 i
位运动员在比赛中的得分。所有得分都 互不相同 。
运动员将根据得分 决定名次 ,其中名次第 1
的运动员得分最高,名次第 2
的运动员得分第 2
高,依此类推。运动员的名次决定了他们的获奖情况:
1
的运动员获金牌 "Gold Medal"
。2
的运动员获银牌 "Silver Medal"
。3
的运动员获铜牌 "Bronze Medal"
。4
到第 n
的运动员,只能获得他们的名次编号(即,名次第 x
的运动员获得编号 "x"
)。使用长度为 n
的数组 answer
返回获奖,其中 answer[i]
是第 i
位运动员的获奖情况。
示例 1:
输入:score = [5,4,3,2,1] 输出:["Gold Medal","Silver Medal","Bronze Medal","4","5"] 解释:名次为 [1st, 2nd, 3rd, 4th, 5th] 。
示例 2:
输入:score = [10,3,8,9,4] 输出:["Gold Medal","5","Bronze Medal","Silver Medal","4"] 解释:名次为 [1st, 5th, 3rd, 2nd, 4th] 。
提示:
n == score.length
1 <= n <= 104
0 <= score[i] <= 106
score
中的所有值 互不相同
优先队列
此处撰写解题思路
class Solution {
public String[] findRelativeRanks(int[] score) {
PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o2[0] - o1[0];
}
});
for (int i = 0; i < score.length; i++) {
queue.add(new int[]{score[i],i});
}
String[] arr = new String[score.length];
String[] top = new String[]{"Gold Medal","Silver Medal","Bronze Medal"};
int i = -1;
while (!queue.isEmpty()){
int[] cur = queue.poll();
if (++i < top.length){
arr[cur[1]] = top[i];
}else{
arr[cur[1]] = (i + 1) + "";
}
}
return arr;
}
}
「快乐前缀」 是在原字符串中既是 非空 前缀也是后缀(不包括原字符串自身)的字符串。
给你一个字符串 s
,请你返回它的 最长快乐前缀。如果不存在满足题意的前缀,则返回一个空字符串 ""
。
示例 1:
输入:s = "level" 输出:"l" 解释:不包括 s 自己,一共有 4 个前缀("l", "le", "lev", "leve")和 4 个后缀("l", "el", "vel", "evel")。最长的既是前缀也是后缀的字符串是 "l" 。
示例 2:
输入:s = "ababab" 输出:"abab" 解释:"abab" 是最长的既是前缀也是后缀的字符串。题目允许前后缀在原字符串中重叠。
提示:
1 <= s.length <= 105
s
只含有小写英文字母KMP模式串预处理方法
其实就是KMP算法中模式串(Pattern)
的预处理算法
整个过程也可以当做是一个动态规划的算法过程来理解,其本质是状态机,额,这块就涉及知识盲区了,大学的知识早就忘记了。
还是回到动态规划
的话题来说吧,比较好理解点
借用一个案例模式串来讲解下
A B A C D A B A B C
我们需要定义的DP数组的含义是,从下标0开始到当前字符结束的子串中,最长的前缀和结尾相同的子串的结束下标,感觉非常绕不像人话。
以上面的子串A B A C D A B A
为例,我们解释一下,这部分内容的 前缀和结尾相同的最长部分为A B A
他在头部的结束下标为 2 ,对应为第二个A
字符所以对应的这部分为dp[7] = 2
,或者简单理解为该子串的长度-1
对于前面没有匹配的部分,我们用-1
来表示,这样我们可以直接先目测得到上面案例字符串算出来的dp[]
数组为
A B A C D A B A B C
-1 -1 0 -1 -1 0 1 2 1 -1
根据上面的结果我们可以看到,dp[i]
的值依赖于 pattern[i]
与 pattern[dp[i-1]+1]
的匹配情况
如果能匹配则dp[i] = dp[i-1] + 1
不能匹配的话则继续与pattern[dp[dp[i-1]]+1]
匹配,不能的话则继续再往前查找
照旧拿上面的案例举个栗子
A B A C D A B A B
-1 -1 0 -1
A B A C D A B A B
0 1 2 ↑
箭头部分的B
与前缀的C
未能匹配,所以继续前移,找到前面的字符A
的dp[7] = 2
的值作为下标的时候dp[2] = 0
的情况下,如下
A B A C D A B A B
-1 -1 0 -1
A B A C D A B A B
0 1 2 ↑
发现能匹配完成,则最终得到对应的dp[8] = dp[2] + 1 = 1
最终我们可以知道数组末尾的值就是题目要求的最长快乐前缀的结束字符下标,在KMP中一般用next[]
数组表示,而不是写成dp[]
数组
class Solution {
public String longestPrefix(String s) {
int[] next = getNextArr(s.toCharArray());
int last = next[next.length - 1];
if (last == -1) return "";
return s.substring(0, last + 1);
}
private int[] getNextArr(char[] arr) {
int[] next = new int[arr.length];
Arrays.fill(next, -1);
int idx = 0;
int p = -1;
while (++idx < arr.length){
while ( p != -1 && arr[p+1] != arr[idx]){
p = next[p];
}
if (arr[p+1] == arr[idx]){
p++;
}
next[idx] = p;
}
return next;
}
}
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
示例 1:
输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5]
示例 2:
输入:head = [1], n = 1 输出:[]
示例 3:
输入:head = [1,2], n = 1 输出:[1]
提示:
sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
进阶:你能尝试使用一趟扫描实现吗?
双指针
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode curN = head;
while (--n >= 0 && curN != null){
curN = curN.next;
}
if (curN==null){
return head.next;
}
ListNode cur = head;
curN = curN.next;
while (curN != null){
cur = cur.next;
curN = curN.next;
}
cur.next = cur.next.next;
return head;
}
}
给你一个字符串 s
,字符串的「能量」定义为:只包含一种字符的最长非空子字符串的长度。
请你返回字符串 s
的 能量。
示例 1:
输入:s = "leetcode" 输出:2 解释:子字符串 "ee" 长度为 2 ,只包含字符 'e' 。
示例 2:
输入:s = "abbcccddddeeeeedcba" 输出:5 解释:子字符串 "eeeee" 长度为 5 ,只包含字符 'e' 。
提示:
1 <= s.length <= 500
s
只包含小写英文字母。双指针,简单步骤分析理解
双指针,简单题
max
长度值,取较大的那个class Solution {
public int maxPower(String s) {
if (s.length() == 0) return 0;
int max = 1;
int left = 0;
int right = 0;
while (left < s.length()){
while (++right < s.length() && s.charAt(right) == s.charAt(right-1)){}
max = Math.max(max,right - left);
left = right;
}
return max;
}
}