删除链表的倒数第n个节点
问题描述
解决思路
先判断特殊情况;
利用快慢指针,进行遍历,先找到快指针,判断是否为最后一个结点,若是最后一个结点了,返回head.next;否则快慢指针一起移动,最后快指针移动到最后一个结点,慢指针为倒数第n个结点的前一个结点,slow.next = slow.next.next;返回head;
java
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @param n int整型
* @return ListNode类
*/
public ListNode removeNthFromEnd (ListNode head, int n) {
// write code here
// write code here
if(head==null || n<1){
return null;
}
ListNode fast=head;
ListNode slow=head;
for(int i=0;i<n;i++){
fast=fast.next;
}
//如果n的值等于链表的长度,直接返回去掉头结点的链表
if(fast==null){
return head.next;
}
//走到倒数的第n+1个结点
while(fast.next!=null){
fast=fast.next;
slow=slow.next;
}
//跳过倒数的第n个结点
slow.next=slow.next.next;
return head;
}
}
设计getMin功能的栈
问题描述
实现一个特殊功能的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。
测试用例
输入
[[1,3],[1,2],[1,1],[3],[2],[3]]
输出
[1,2]
有三种操作种类,op1表示push,op2表示pop,op3表示getMin。你需要返回和op3出现次数一样多的数组,表示每次getMin的答案
1<=操作总数<=1000000
-1000000<=每个操作数<=1000000
数据保证没有不合法的操作
解决思路
读懂题很重要,半天没读懂题目。泪目。
AC
python
#
# return a array which include all ans for op3
# @param op int整型二维数组 operator
# @return int整型一维数组
#
class Solution:
def getMinStack(self , op ):
res = []
stack1 = []
stack2 = []
for i in range(len(op)):
if op[i][0]==1:
stack1.append(op[i][1])
stack2.append(op[i][1])
stack2.sort()
elif op[i][0]==2:
temp = stack1.pop()
stack2.remove(temp)
stack2.sort()
elif op[i][0]==3:
temp = stack2[0]
res.append(temp)
return res
滑动窗口的最大值
问题描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
窗口大于数组长度的时候,返回空。
测试用例
输入
[2,3,4,2,6,2,5,1],3
输出
[4,4,6,6,6,5]
解决思路
先判断特殊情况;
控制一个窗口大小,移动窗口,得到窗口中最大值,加入结果集;
AC
java
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size) {
ArrayList<Integer> res = new ArrayList<Integer>();
if(size>num.length||size<1||num==null){
return res;
}
for (int i = 0; i < num.length+1-size; i++) {
int max_temp = num[i];
for(int j = i;j<i+size;j++){
max_temp = Math.max(max_temp,num[j]);
}
res.add(max_temp);
}
return res;
}
}
判断链表中是否有环
问题描述
判断给定的链表中是否有环。如果有环则返回true,否则返回false。
你能给出空间复杂度O(1)的解法么?
解决思路
-
快慢指针
具体地,我们定义两个指针,一快一满。慢指针每次只移动一步,而快指针每次移动两步。初始时,慢指针在位置 head,而快指针在位置 head.next。这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该链表为环形链表。否则快指针将到达链表尾部,该链表不为环形链表。
-
set保存地址,判断是否有重复地址;
AC
java
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if(head==null){
return false;
}
ListNode fast = head;
ListNode slow = head;
while(fast!=null && fast.next!=null){
slow = slow.next;
fast = fast.next.next;
if(slow==fast){
return true;
}
}
return false;
}
}
python
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
# @param head ListNode类
# @return bool布尔型
#
class Solution:
def hasCycle(self , head ):
# write code here
if not head:
return False
set_id = set()
p = head
while p:
if id(p) in set_id:
return True
else:
set_id.add(id(p))
p = p.next
return False
删除有序数组中的重复项
问题描述
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
测试用例
示例 1:
输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。
示例 2:
输入:nums = [0,0,1,1,1,1,2,3,3]
输出:7, nums = [0,0,1,1,2,3,3]
解释:函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。 不需要考虑数组中超出新长度后面的元素。
解决思路
认真读题,每个元素最多出现两次;
while循环修改可变list;
AC
python
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
i = 2
if len(nums)<=1:
return len(nums)
while i <len(nums):
if nums[i]==nums[i-1] and nums[i-2] ==nums[i-1]:
nums.pop(i)
else:
i+=1
return len(nums)
最长递增子序列
问题描述
给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。
子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。
测试用例
示例 1:
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:
输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:
输入:nums = [7,7,7,7,7,7,7]
输出:1
解决思路
动态规划:dp[i]表示以num[i]结尾的满足条件的长度。
动态转移方程为:
dp[i] = max(dp[i],dp[j]+1),0<j<i,且num[j]<num[i];
AC
python
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
if not nums:
return 0
dp = [1]*len(nums)
for i in range(len(nums)):
for j in range(i):
if nums[i]>nums[j]:
dp[i] = max(dp[i],dp[j]+1)
return max(dp)
找到字符串的最长无重复子串
问题描述
给定一个数组arr,返回arr的最长无的重复子串的长度(无重复指的是所有数字都不相同)。
测试用例
输入
[2,3,4,5]
返回值
4
示例2
输入
[2,2,3,4,3]
返回值
3
解决思路
对数组遍历, 并使用临时数组保存遍历过的元素, 如果元素出现,则比较并保存当前的最大长度,同时临时序列保留相同元素后的无重复序列继续遍历
使用双指针,如果新的元素 与起止指针范围内的元素重复,就暂存当前的无重复序列长度, 并将起始指针移动到重复元素后
AC
python
#
#
# @param arr int整型一维数组 the array
# @return int整型
#
class Solution:
def maxLength(self , arr ):
# write code here
seen = []
max_length = 0
i = 0
while i<len(arr):
if arr[i] not in seen:
seen.append(arr[i])
i += 1
else:
max_length = max(max_length,len(seen))
index = seen.index(arr[i])
seen = seen[index+1:]
seen.append(arr[i])
i +=1
return max(max_length,len(seen))
最长公共子序列
问题描述
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
测试用例
示例 1:
输入:text1 = "abcde", text2 = "ace"
输出:3
解释:最长公共子序列是 "ace" ,它的长度为 3 。
示例 2:
输入:text1 = "abc", text2 = "abc"
输出:3
解释:最长公共子序列是 "abc" ,它的长度为 3 。
示例 3:
输入:text1 = "abc", text2 = "def"
输出:0
解释:两个字符串没有公共子序列,返回 0
解决思路
动态规划;
AC
java
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length();
int n = text2.length();
int [][] dp = new int[m+1][n+1];
for (int i = 1; i <=m ; i++) {
for (int j = 1; j <=n ; j++) {
if (text1.charAt(i-1)==text2.charAt(j-1)){
//更新状态方程
dp[i][j] = dp[i-1][j-1]+1;
}else{
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
}
}
}
return dp[m][n];
}
}
最长公共子串
问题描述
给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。
测试用例
输入
"1AB2345CD","12345EF"
返回值
"2345"
解决思路
跟最长公共子序列类似,不过状态转移方程不同:
AC
java
import java.util.*;
public class Solution {
/**
* longest common substring
* @param str1 string字符串 the string
* @param str2 string字符串 the string
* @return string字符串
*/
public String LCS (String str1, String str2) {
// write code here
int m = str1.length();
int n = str2.length();
char[] arr1 = str1.toCharArray();
char[] arr2 = str2.toCharArray();
int[][] dp = new int[m+1][n+1];
int res = 0;
int end = 0;
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(arr1[i-1]==arr2[j-1]){
dp[i][j] = dp[i-1][j-1]+1;
if(res<dp[i][j]){
end = j;
res = dp[i][j];
}
}else{
dp[i][j] = 0;
}
}
}
return str2.substring(end-res,end);
}
}
设计LRU缓存结构
问题描述
设计LRU缓存结构,该结构在构造时确定大小,假设大小为K,并有如下两个功能
- set(key, value):将记录(key, value)插入该结构
- get(key):返回key对应的value值
[要求]
-
set和get方法的时间复杂度为O(1)
-
某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的。
-
当缓存的大小超过K时,移除最不经常使用的记录,即set或get最久远的。
若opt=1,接下来两个整数x, y,表示set(x, y)
若opt=2,接下来一个整数x,表示get(x),若x未出现过或已被移除,则返回-1
对于每个操作2,输出一个答案
测试用例
输入
[[1,1,1],[1,2,2],[1,3,2],[2,1],[1,4,4],[2,2]],3
返回值
[1,-1]
说明
第一次操作后:最常使用的记录为("1", 1)
第二次操作后:最常使用的记录为("2", 2),("1", 1)变为最不常用的
第三次操作后:最常使用的记录为("3", 2),("1", 1)还是最不常用的
第四次操作后:最常用的记录为("1", 1),("2", 2)变为最不常用的
第五次操作后:大小超过了3,所以移除此时最不常使用的记录("2", 2),加入记录("4", 4),并且为最常使用的记录,然后("3", 2)变为最不常使用的记录
解决思路
- LinkedHashMap可以作为LRU来使用,但是要重写removeEldestEntry方法。
重写LinkedHashMap中的removeEldestEntry方法,当LRU中元素多余k个时,删除最老的节点(即最不经常使用的元素); - LinkedHashMap第三个参数置位true
- arrayList转换成数组类型,返回值
AC
java
import java.util.*;
public class Solution {
/**
* lru design
* @param operators int整型二维数组 the ops
* @param k int整型 the k
* @return int整型一维数组
*/
LinkedHashMap<Integer,Integer> linkedHashMap;
public int[] LRU (int[][] operators, int k) {
// write code here
linkedHashMap = new LinkedHashMap<Integer,Integer>(k,0.75f,true){
@Override
protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
return linkedHashMap.size()>k;
}
};
ArrayList<Integer> arrayList = new ArrayList<>();
for(int i = 0;i<operators.length;i++){
if(operators[i][0]==1){
//存入
set(operators[i][1],operators[i][2]);
}else if(operators[i][0]==2){
arrayList.add(get(operators[i][1]));
}
}
int [] res = new int[arrayList.size()];
int i = 0;
for (int x:arrayList){
res[i++] = x;
}
return res;
}
public int get(int key){
return linkedHashMap.getOrDefault(key,-1);
}
public void set(int key,int value){
linkedHashMap.put(key,value);
}
}