每日算法

删除链表的倒数第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)的解法么?

解决思路
  1. 快慢指针

    具体地,我们定义两个指针,一快一满。慢指针每次只移动一步,而快指针每次移动两步。初始时,慢指针在位置 head,而快指针在位置 head.next。这样一来,如果在移动的过程中,快指针反过来追上慢指针,就说明该链表为环形链表。否则快指针将到达链表尾部,该链表不为环形链表。

  2. 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值

[要求]

  1. set和get方法的时间复杂度为O(1)

  2. 某个key的set或get操作一旦发生,认为这个key的记录成了最常使用的。

  3. 当缓存的大小超过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)变为最不常使用的记录
解决思路
  1. LinkedHashMap可以作为LRU来使用,但是要重写removeEldestEntry方法。
    重写LinkedHashMap中的removeEldestEntry方法,当LRU中元素多余k个时,删除最老的节点(即最不经常使用的元素);
  2. LinkedHashMap第三个参数置位true
  3. 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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值