1.链表反转。给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
输入: head = [1,2,3,4,5]
输出: [5,4,3,2,1]
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode now = head;
while(now != null){
ListNode next = now.next;
//next指针先指向头结点的下一个节点
now.next = pre;
//当前节点的指针指向前一个结点,
pre = now;
now = next;
}
head = pre;
return pre;
}
}
2 LRU 缓存(待做)
请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类:
- LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存
- int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
- void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。 函数 get 和 put 必须以 O(1) 的平均时间复杂度运行。
输入
["LRUCache", "put", "put", "get", "put", "get", "put", "get", "get", "get"]
[[2], [1, 1], [2, 2], [1], [3, 3], [2], [4, 4], [1], [3], [4]]
输出
[null, null, null, 1, null, -1, null, -1, 3, 4]
解释
LRUCache lRUCache = new LRUCache(2);
lRUCache.put(1, 1); // 缓存是 {1=1}
lRUCache.put(2, 2); // 缓存是 {1=1, 2=2}
lRUCache.get(1); // 返回 1
lRUCache.put(3, 3); // 该操作会使得关键字 2 作废,缓存是 {1=1, 3=3}
lRUCache.get(2); // 返回 -1 (未找到)
lRUCache.put(4, 4); // 该操作会使得关键字 1 作废,缓存是 {4=4, 3=3}
lRUCache.get(1); // 返回 -1 (未找到)
lRUCache.get(3); // 返回 3
lRUCache.get(4); // 返回 4
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.remove(s.charAt(i - 1));
}
while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
// 不断地移动右指针
occ.add(s.charAt(rk + 1));
++rk;
}
// 第 i 到 rk 个字符是一个极长的无重复字符子串
ans = Math.max(ans, rk - i + 1);
}
return ans;
3 合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。
请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n 。
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
for(int i = 0;i < n;i++){
nums1[m + i] = nums2[i];
//m++;
}
Arrays.sort(nums1);
}
}
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int p1 = m - 1;
int p2 = n - 1;
int tail = m + n - 1;
int curr = 0;
while(p1 >= 0 || p2 >= 0 ){
if(p1 == -1){
curr = nums2[p2]; p2--;
}else if(p2 == -1){
curr = nums1[p1]; p1--;
}else if(nums1[p1] > nums2[p2]){
curr = nums1[p1]; p1--;
}else{
curr = nums2[p2]; p2--;
}
nums1[tail--] = curr;
}
}
}
4 最大子数组和
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6 。
输入: nums = [1]
输出: 1
输入: nums = [5,4,-1,7,8]
输出: 23
class Solution {
public int maxSubArray(int[] nums) {
int pre = 0;
int maxAns = nums[0];
for(int i:nums){
//当前和.取{当前值,之前和}最大值
pre = Math.max(i,pre + i);
//最大和取{当前和,当前值}最大值
maxAns = Math.max(pre, maxAns);
}
return maxAns;
}
}
5 两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] point = new int[2];
for(int i = 0;i < nums.length;i++){
for(int j = i + 1;j < nums.length;j++){
if(target == nums[i] + nums[j]){
point[0] = i;
point[1] = j;
}
}
}
return point;
}
}
class Solution {
public int[] twoSum(int[] nums, int target) {
//Integer, Integer:数值,下标
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i = 0;i < nums.length;i++){
if(map.containsKey(target - nums[i])){
return new int[]{map.get(target - nums[i]),i};
}
map.put(nums[i],i);
}
return new int[0];
}
}
6 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode prehead = new ListNode(-1);
ListNode pre = prehead;
while(list1 != null && list2 != null){
if(list2.val <= list1.val){
//p2插入
pre.next = list2;
list2 = list2.next;
}else{
pre.next = list1;
list1 = list1.next;
}
pre = pre.next;
}
pre.next = list1 == null?list2:list1;
return prehead.next;
}
}
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if(list1 == null){
return list2;
}else if(list2 == null){
return list1;
}else if(list1.val < list2.val){
//p1插入
list1.next = mergeTwoLists(list1.next, list2);
return list1;
}else{
list2.next = mergeTwoLists( list1, list2.next);
return list2;
}
}
}
O(∩_∩)O qtmd
7 有效括号
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。
示例 1:
输入:s = "()"
输出:true
示例 2:
输入:s = "()[]{}"
输出:true
示例 3:
输入:s = "(]"
输出:false
示例 4:
输入:s = "([)]"
输出:false
示例 5:
输入:s = "{[]}"
输出:true
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<Character>();
for(Character a:s.toCharArray()){
if(a == '(' || a == '[' || a == '{'){
stack.push(a);
}
else{
if(stack.isEmpty()){
return false;
}
else{
char temp = (char)stack.pop();
if((a == ')' && temp == '(') || ((a == ']' && temp == '[')) || ((a == '}' && temp == '{') ))
{}
else {return false;}
}
}
}
if(stack.isEmpty()){ return true;}
return false;
}
}
class Solution {
public boolean isValid(String s) {
Stack<Character> stack = new Stack<Character>();
int n = s.length();
if (n % 2 == 1) {
return false;
}
for(Character a:s.toCharArray()){
if(a == '(' || a == '[' || a == '{'){
stack.push(a);
}
else{
if(!stack.isEmpty()){
char temp = (char)stack.pop();
if((a == ')' && temp == '(') || ((a == ']' && temp == '[')) || ((a == '}' && temp == '{') ))
{continue;}
else {return false;}
}
return false;
}
}
if(stack.isEmpty()){ return true;}
return false;
}
}
class Solution {
public boolean isValid(String s) {
Map<Character, Character> map = new HashMap<>();
map.put('(', ')');
map.put('[', ']');
map.put('{', '}');
LinkedList<Character> stack = new LinkedList<>();
for (char c : s.toCharArray()) {
if (map.containsKey(c)) {
stack.add(c);
} else {
if (stack.isEmpty() || map.get(stack.removeLast()) != c) {
return false;
}
}
}
return stack.isEmpty();
}
}
8#### 买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
示例 1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
//暴力算法超时
class Solution {
public int maxProfit(int[] prices) {
int max = 0;
for(int i = 0;i < prices.length;i++){
for(int j = i;j < prices.length;j++){
if(prices[j] - prices[i] > max)
{
max = prices[j] - prices[i];
}
}
}
return max;
}
}
class Solution {
public int maxProfit(int[] prices) {
int max = 0;
int min = prices[0];
for(int i = 0;i < prices.length;i++){
if(prices[i] < min){
min = prices[i];
}else if(prices[i] - min > max)
{
max = prices[i] - min;
}
}
return max;
}
}
9 相交链表
给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。
自定义评测:
评测系统 的输入如下(你设计的程序 不适用 此输入):
- intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
- listA - 第一个链表
- listB - 第二个链表
- skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
- skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数 评测系统将根据这些输入创建链式数据结构,并将两个头节点 headA 和 headB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案 。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
//双指针
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null){
return null;
}
ListNode pa = headA, pb = headB;
while(pa != pb){
if(pa == null){
pa = headB;pb = pb.next;
}else if(pb == null){
pb = headA;pa = pa.next;
}else{
pa = pa.next;pb = pb.next;
}
}
return pa;
}
}
//双指针优化
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if(headA == null || headB == null){
return null;
}
ListNode pa = headA, pb = headB;
while(pa != pb){
// if(pa == null){
// pa = headB;pb = pb.next;
// }else if(pb == null){
// pb = headA;pa = pa.next;
// }else{
// pa = pa.next;pb = pb.next;
// }
pa = pa == null?headB:pa.next;
pb = pb == null?headA:pb.next;
}
return pa;
}
}
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
Set<ListNode> con = new HashSet<ListNode>();
ListNode pa = headA;
while(pa != null){
con.add(pa);
pa = pa.next;
}
ListNode pb = headB;
while(pb != null){
if(con.contains(pb)){return pb;}
pb = pb.next;
}
return null;
}
}
10 环形链表
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
如果链表中存在环,则返回 true 。 否则,返回 false 。
/**
* 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) {
Set<ListNode> circle = new HashSet<ListNode>();
ListNode p = head;
while(p != null ){
if( !circle.contains(p)){
circle.add(p);
p = p.next;
}else{
return true;
}
}
return false;
}
}