【算法】实验室2024第一次考核复盘

【算法】实验室2024第一次考核复盘

本篇博客将遵循从易到难的原则,依次解析这几道考核题目。

原题链接:

125. 验证回文串 - 力扣(LeetCode)

image-20240421160727408

使用两个指针ij分别从字符串的两端开始,i从左往右,j从右往左。通过两个while循环,ij会跳过所有非字母和非数字的字符。当i小于j时,比较ij指向的字符(转换为小写后),如果不相等,则直接返回false,表示字符串不是回文。

如果相等,则ij各自向中间移动一位,继续比较下一对字符。

如果所有对应的字符都相等,当i大于等于j时,循环结束,返回true,表示字符串是回文。

class Solution {
    public boolean isPalindrome(String s) {
        int i = 0, j = s.length() - 1;
        while(i < j){
            while(i < j && !Character.isLetterOrDigit(s.charAt(i))) i++;
            while(i < j && !Character.isLetterOrDigit(s.charAt(j))) j--;
            if(Character.toLowerCase(s.charAt(i)) != Character.toLowerCase(s.charAt(j))) return false;
            i++; 
            j--;
        }
        return true;
    }
}

原题链接:

392. 判断子序列 - 力扣(LeetCode)

image-20240421160742198

如果s的长度为0,即s为空字符串,那么它自然地是任何字符串的子序列,因此返回true

使用两个指针ij分别遍历字符串sti从0开始,j也从0开始。

j小于t的长度时,循环继续。在每次循环中,比较s中的当前字符(s.charAt(i))和t中的当前字符(t.charAt(j))。

如果这两个字符相等,i增加1(指向s的下一个字符),并且检查是否已经遍历完s的所有字符。如果是,则返回true,因为st的子序列。

如果j遍历完ti没有遍历完s,则s不是t的子序列,方法返回false

class Solution {
    public boolean isSubsequence(String s, String t) {
        if (s.length() == 0) return true;
        for (int i = 0, j = 0; j < t.length(); j++) {
            if (s.charAt(i) == t.charAt(j)) {
                // 若已经遍历完 s ,则提前返回 true
                if (++i == s.length())
                    return true;
            }
        }
        return false;
    }
}

原题链接:

35. 搜索插入位置 - 力扣(LeetCode)

image-20240421160759849

使用两个指针leftright来表示搜索区间,初始时left为0,right为数组长度。

使用while循环进行二分查找,当left小于right时循环继续。

在每次循环中,计算中间索引mid,然后比较nums[mid]target的值。

如果nums[mid]等于target,则找到了目标值,但代码中缺少了返回mid的语句。

如果nums[mid]小于target,则将left设置为mid + 1,表示搜索区间移动到mid的右侧。

如果nums[mid]大于target,则将right设置为mid,表示搜索区间移动到mid的左侧。

leftright相遇时,循环结束,此时left即为target应该插入的位置。

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0, right = nums.length;
        while(left < right) {
            int mid = (left + right) / 2;
            if(nums[mid] == target) {
            } else if(nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        return 0;
    }
}

原题链接:

147. 对链表进行插入排序 - 力扣(LeetCode)

image-20240421160817172

创建一个哑节点(dummy node)dummy,其值设置为0,它的作用是简化边界情况的处理,因为哑节点不包含在链表的真实元素中,但是可以作为头节点的前一个节点。

使用pre指针指向哑节点,cur指针从head开始遍历链表。

对于链表中的每个节点(cur),在dummypre之间找到合适的插入位置。这是通过内部的while循环实现的,循环条件是pre.next不为空且pre.next.val小于cur.val

找到插入位置后,将cur节点插入到pre.next之前。

更新pre为哑节点,以便为下一个节点的插入做准备。

更新cur为下一个节点,继续遍历链表。

最后,返回哑节点的下一个节点dummy.next,即为排序后的链表的头节点。

class Solution {
    public ListNode insertionSortList(ListNode head) {
        ListNode dummy = new ListNode(0);
        ListNode pre = dummy;
        ListNode cur = head;
        while (cur != null) {
            ListNode tmp = cur.next;
            while (pre.next != null && pre.next.val < cur.val) pre = pre.next;
            cur.next = pre.next;
            pre.next = cur;
            pre = dummy;
            cur = tmp;
        }
        return dummy.next;
    }
}

原题链接:

125. 验证回文串 - 力扣(LeetCode)

image-20240421160910165

遍历字符串中的每个字符,对于大写字母,将其转换为小写(通过ASCII值减去32实现),对于小写字母和数字,直接保留。

过滤掉非字母数字字符,并在过滤后的字符数组中更新字符位置,通过index指针来记录有效字符的个数。

使用两个指针leftright分别从过滤后的字符数组的两端开始,向中间遍历。

如果两端的字符不相等,则返回false,表示字符串不是回文。

如果所有对应的字符都相等,循环结束后返回true,表示字符串是回文。

class Solution {
    public boolean isPalindrome(String str) {
        char[] s = str.toCharArray();
        int n = s.length;
        int index = 0;
        for (int i = 0; i < n; i++) {
            if (s[i] >= 'A' && s[i] <= 'Z') {
                // 大写
                s[index++] = (char) (s[i] + 32);
            } else if ((s[i] >= 'a' && s[i] <= 'z') ||
                    (s[i] <= '9' && s[i] >= '0')) {
                //  小写和数字
                s[index++] = s[i];
            }
        }
        // System.out.println(new String(s, 0, index));
        int left = 0, right = index - 1;
        while (left < right) {
            if (s[left] != s[right]) return false;
            left++;
            right--;
        }
        return true;
    }
}

原题链接:

61. 旋转链表 - 力扣(LeetCode)

image-20240421160921755

找到插入点,分开两个链表,再首尾相接即可。

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if(head == null|| k == 0){
            return head;
        }
        ListNode fast = head;
        ListNode slow = head;
        int n = 0;
        while(fast != null){
            fast = fast.next;
            n++;
        }
        if(k % n == 0){
            return head;
        }
        fast = head;
        for(int i = k % n;i >= 0;i--){
            fast = fast.next;
        }
        while(fast != null){
            fast = fast.next;
            slow = slow.next;
        }
        //qiefen
        ListNode newHead = slow.next;
        slow.next = null;
        ListNode pmov = newHead;
        while(pmov != null && pmov.next != null){
            pmov = pmov.next;
        }
        pmov.next = head;
        return newHead;
    }
}

原题链接:

232. 用栈实现队列 - 力扣(LeetCode)

image-20240421160939198

【算法】栈作队时队亦栈,进为出处出也进-CSDN博客

这篇博客中,我对本题作了比较详细的阐述,就不再赘述啦~

typedef struct {
    int stackIn[200];
    int stackOut[200];
    int topIn;
    int topOut;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* que = (MyQueue*)malloc(sizeof(MyQueue));
    que->topIn = 0;
    que->topOut = 0;
    return que;
}

void myQueuePush(MyQueue* obj, int x) {
    obj->stackIn[obj->topIn] = x;
    obj->topIn = obj->topIn+1;
}

int myQueuePop(MyQueue* obj) {
    //将in栈中元素压入out栈
    int inTop = obj->topIn;
    int outTop = obj->topOut;
    if (outTop == 0) {
        while (inTop > 0) {
            obj->stackOut[outTop++] = obj->stackIn[--inTop];
        }
    }
    //出栈(出队)
    int top = obj->stackOut[--outTop];
    //将out栈中元素压回in栈
    while (outTop > 0) {
        obj->stackIn[inTop++] = obj->stackOut[--outTop];
    }
    obj->topIn = inTop;
    obj->topOut = outTop;
    return top;
}

int myQueuePeek(MyQueue* obj) {
    //队列首个元素即为in栈中最底下的元素
    return obj->stackIn[0];
}

bool myQueueEmpty(MyQueue* obj) {
    if(obj->topIn == 0){ 
        return true;
    }else{
        return false;
    }
}

void myQueueFree(MyQueue* obj) {
    obj->topIn = 0;
    obj->topOut = 0;
}

原题链接:

309. 买卖股票的最佳时机含冷冻期 - 力扣(LeetCode)

image-20240421160956454

如果数组长度小于等于1,意味着没有交易发生,返回0作为利润。

创建一个二维整数数组dp,其中dp[i][j]表示在第i天时,采用第j种策略能够获得的最大利润。数组的三个状态分别代表:

  • dp[i][0]:第i天不持有股票的最大利润。
  • dp[i][1]:第i天持有股票的最大利润。
  • dp[i][2]:第i天已经卖出股票后的最大利润(即在第i天或之前卖出)。

初始化dp[0]数组,其中dp[0][0]为0(不持有股票),dp[0][1]-prices[0](购买股票),dp[0][2]为0(已经卖出股票)。

遍历price数组,从第1天到第n-1天,更新dp数组。对于每一天i:

  • dp[i][0]更新为不持有股票的最大利润,即持有或不持有股票的最大利润(dp[i-1][0]dp[i-1][2])。
  • dp[i][1]更新为持有股票的最大利润,即前一天不持有股票的情况下减去当前天股票价格(dp[i-1][0] - prices[i])或前一天持有股票的最大利润(dp[i-1][1])。
  • dp[i][2]更新为卖出股票后的最大利润,即持有股票的情况下加上当前天股票价格(dp[i-1][1] + prices[i])。

最后,返回第n-1天不持有股票或已经卖出股票的最大利润(dp[n-1][0]dp[n-1][2])。

class Solution {
    public int maxProfit(int[] prices) {
        int n=prices.length;
        if(n<=1) return 0;
        int [][] dp=new int[n][3];
        dp[0][0]=0;
        dp[0][1]=-1*prices[0];
        dp[0][2]=0;
        for(int i=1;i<n;i++){//从[1]...[n-1]
          dp[i][0]=Math.max(dp[i-1][0],dp[i-1][2]);
            dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]-prices[i]);
            dp[i][2]=dp[i-1][1]+prices[i];

        }
        return Math.max(dp[n-1][0],dp[n-1][2]);
    }
}

原题链接:

238. 除自身以外数组的乘积 - 力扣(LeetCode)

image-20240421161007356

如果数组长度为0,则直接返回空数组,因为没有任何元素可以计算乘积。

创建一个与nums同样长度的数组ans,用于存储每个元素的乘积结果。数组的第一个元素初始化为1,因为任何数与1相乘都等于其本身。

使用一个临时变量tmp来存储从数组末尾开始的累积乘积。

首先,通过一个循环计算出ans中每个元素除了其自身以外左侧所有元素的乘积。

然后,通过另一个循环从数组末尾开始,更新ans中每个元素的乘积,使其包含右侧所有元素的乘积。

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int len = nums.length;
        if (len == 0) return new int[0];
        int[] ans = new int[len];
        ans[0] = 1;
        int tmp = 1;
        for (int i = 1; i < len; i++) {
            ans[i] = ans[i - 1] * nums[i - 1];
        }
        for (int i = len - 2; i >= 0; i--) {
            tmp *= nums[i + 1];
            ans[i] *= tmp;
        }
        return ans;
    }
}

原题链接:

73. 矩阵置零 - 力扣(LeetCode)

image-20240421161016954

获取矩阵的行数m和列数n

创建两个辅助数组hashmhashn,分别用于记录哪些行和列需要被置为0。

首先,遍历整个矩阵,如果发现某个元素为0,则在hashmhashn中标记对应的行和列。

然后,遍历hashm,如果某个索引的值为1,则将矩阵中对应行的所有元素置为0。

最后,遍历hashn,如果某个索引的值为1,则将矩阵中对应列的所有元素置为0。

class Solution {
    public void setZeroes(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        int[] hashm = new int[m];
        int[] hashn = new int[n];
        for(int i = 0;i < m;++i){
            for(int j = 0;j < n;++j){
                if(matrix[i][j] == 0){
                    hashm[i] = 1;
                    hashn[j] = 1;
                }
            }
        }
        for(int i = 0;i < m;++i){
            if(hashm[i] == 1){ 
                System.out.println(i);
                for(int z = 0;z < n;++z){
                    matrix[i][z] = 0;
                }
            }
        }
        for(int j = 0;j < n;++j){
            if(hashn[j] == 1){
                System.out.println(j);
                for(int z = 0;z < m;++z){
                    matrix[z][j] = 0;
                }
            }
        }
    }
}

原题链接:

394. 字符串解码 - 力扣(LeetCode)

在这里插入图片描述

使用一个栈st来存储解码过程中的字符和数字。

使用变量cnt来记录当前处理到字符串s的哪个位置。

使用变量ans来存储最终解码后的字符串。

使用循环遍历字符串s,根据当前字符tmp的类型进行不同的处理:

  • 如果tmp是字母或数字,将其压入栈st
  • 如果tmp"[",将其压入栈,并继续读取下一个字符。
  • 如果tmp是"]",开始解码操作:
    • 弹出栈中直到遇到"["的所有字符,并反转这个字符串,得到需要重复的字符串strtmp
    • 继续弹出栈中直到所有数字被弹出,反转这个字符串得到numstr
    • numstr转换为整数num,表示需要重复的次数。
    • strtmp按照num次重复,并将重复后的字符压回栈中。
  • 如果tmp不在上述情况中,循环继续。
class Solution {
    public String decodeString(String s) {
        Stack<Character> st = new Stack<>();
        String ans = "";
        int cnt = 0;
        while(cnt != s.length()){
            char tmp = s.charAt(cnt);

            //如果是数字
            if(tmp <= '9' || tmp >= 'a'){
                st.push(tmp);
                cnt++;
            }else if(tmp == '['){
                st.push(tmp);
                cnt++;
            }else if(tmp == ']'){
                cnt++;
                String strtmp = "";
                while(st.peek() != '['){
                    strtmp += st.pop();
                }
                st.pop();
                String numstr = "";
                while(!st.isEmpty() && st.peek() <= '9'){
                    numstr += st.pop();
                }
                String numstrtrue = "";
                int n = numstr.length()-1;
                while(n >= 0){
                    numstrtrue += numstr.charAt(n);
                    n--;
                }
                int num = Integer.parseInt(numstrtrue);
                for(int i = 0;i < num;++i){
                    for(int j = strtmp.length()-1;j >= 0;--j){
                        st.push(strtmp.charAt(j));
                    }
                }
                
            }else{
                continue;
            }
        }
        for(char ch : st){
            ans += ch;
        }
        return ans;
    }
}

原题链接:

23. 合并 K 个升序链表 - 力扣(LeetCode)

image-20240421161055616

合并两个有序链表升级版~

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists.length == 0) return null;
        if(lists.length == 1) return lists[0];
        for(int i = 1;i < lists.length;++i){
            lists[0] = MergeLists(lists[0],lists[i]);
        }
        return lists[0];
    }
    public ListNode MergeLists(ListNode l1,ListNode l2){
        ListNode dummy = new ListNode(0);
        ListNode pmov = dummy;
        while(l1 != null && l2 != null){
            if(l1.val < l2.val){
                pmov.next = l1;
                l1 = l1.next;
            }else{
                pmov.next = l2;
                l2 = l2.next;
            }
            
            pmov = pmov.next;
        }
        if(l1 == null){
            pmov.next = l2;
        }else{
            pmov.next = l1;
        }
        return dummy.next;
    }
}
  • 30
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值