算法集锦(NO.4)高频习题

算法集锦(NO.4)

高频习题

吃透吃精

跳跃游戏 II
给定一个非负整数数组,你最初位于数组的第一个位置。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
你的目标是使用最少的跳跃次数到达数组的最后一个位置。
假设你总是可以到达数组的最后一个位置。

示例 1:

输入: [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:

输入: [2,3,0,1,4]
输出: 2

提示:

1 <= nums.length <= 1000
0 <= nums[i] <= 105

方法一:
使用辅助数组,来进行动态规划存储,每次存储步数最小。

class Solution {
    public int jump(int[] nums) {
    //设立一个辅助数组
        int [] numsNext = new int [nums.length+1];
        //将数组中的元素都填充至最大
        Arrays.fill(numsNext,Integer.MAX_VALUE);
        //首元素为0(保护),1为0(1为始发点)
        numsNext[0]=0;
        numsNext[1]=0;
        for(int i=1;i<numsNext.length;i++){
        //用j来表示后移步,只要在nums【i-1】当前节点的辐射范围内
            for(int j=1;j<=nums[i-1]&&(i+j<numsNext.length);j++){
            //步数取小
                numsNext[j+i]=Math.min(numsNext[j+i],numsNext[i]+1);
            }
        }
        return numsNext[nums.length];
    }
}

算法集锦(NO.4)高频习题_第1张图片
时间复杂度O(M*N),空间复杂度O(N)

方法二:
贪心算法,用贪心思想来解决问题。寻求可以抵达目标点最远的点,然后步数+1,更新目标点。

class Solution {
    public int jump(int[] nums) {
    //标记目标节点
        int position = nums.length - 1;
        //步数为0
        int steps = 0;
        //当目标节点没有初始化为首节点时,不断循环
        while (position > 0) {
        //找出距离目标节点最远的节点
            for (int i = 0; i < position; i++) {
                if (i + nums[i] >= position) {
                //更新目标节点
                    position = i;
                    //步数增加
                    steps++;
                    break;
                }
            }
        }
        return steps;
    }
}

算法集锦(NO.4)高频习题_第2张图片
时间复杂度O(N^2),空间复杂度O(1)

方法三:

class Solution {
    public int jump(int[] nums) {
    //终结节点
        int length = nums.length;
        //用来保存每次步数的最大长度
        int end = 0;
        //当前最大长度
        int maxPosition = 0; 
        //步数统计
        int steps = 0;
        for (int i = 0; i < length - 1; i++) {
            maxPosition = Math.max(maxPosition, i + nums[i]); 
           //当i==end时候,来更新每步的最长长度
            if (i == end) {
                end = maxPosition;
                steps++;
            }
        }
        return steps;
    }
}

算法集锦(NO.4)高频习题_第3张图片
时间复杂度O(N),空间复杂度O(1)

最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。

示例 1:

输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
示例 2:

输入:s = “cbbd”
输出:“bb”
示例 3:

输入:s = “a”
输出:“a”
示例 4:

输入:s = “ac”
输出:“a”

提示:

1 <= s.length <= 1000
s 仅由数字和英文字母(大写和/或小写)组成

方法一:
中心扩散:遍历每个节点,考虑到其边界情况,单点中心和双点中心两种方法。

class Solution {
    public String longestPalindrome(String s) {
        if(s.length()==0){
            return s;
        }
        //使用str来进行最后结果的存储
        String str="";
        for(int i=0;i<s.length();i++){
        //当i节点为中心时
            str = longestList(s,str,i,i);
            //当i和i+1为中心时
            str = longestList(s,str,i,i+1);
        }
        return str;
    }
    public String longestList(String s,String str,int left,int right){
    //当右指针超过左边界或者左右指针值不同时,直接返回
        if(right>=s.length()||s.charAt(left)!=s.charAt(right)){
            return str;
        }
        //当左右指针都在范围区间内则可以循环
        while(left>=0&&right<s.length()){
        //当左右指针值相同时,扩大范围
            if(s.charAt(left)==s.charAt(right)){
                left--;
                right++;
            }else{
            //否则直接跳出循环
                break;
            }
        }
        //当此回文范围大于已存范围则扩大
        if(right-left-1>str.length()){
            str = s.substring(left+1,right);
        }
        return str;
    }
}

算法集锦(NO.4)高频习题_第4张图片

在这里插入图片描述
方法二:
动态规划,借鉴一下官方的,动态规划的关键在于动态区间和动态规划式

public class Solution {

    public String longestPalindrome(String s) {
        int len = s.length();
        if (len < 2) {
            return s;
        }

        int maxLen = 1;
        int begin = 0;
        // dp[i][j] 表示 s[i..j] 是否是回文串
        boolean[][] dp = new boolean[len][len];
        // 初始化:所有长度为 1 的子串都是回文串
        for (int i = 0; i < len; i++) {
            dp[i][i] = true;
        }

        char[] charArray = s.toCharArray();
        // 递推开始
        // 先枚举子串长度
        for (int L = 2; L <= len; L++) {
            // 枚举左边界,左边界的上限设置可以宽松一些
            for (int i = 0; i < len; i++) {
                // 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
                int j = L + i - 1;
                // 如果右边界越界,就可以退出当前循环
                if (j >= len) {
                    break;
                }

                if (charArray[i] != charArray[j]) {
                    dp[i][j] = false;
                } else {
                    if (j - i < 3) {
                        dp[i][j] = true;
                    } else {
                        dp[i][j] = dp[i + 1][j - 1];
                    }
                }

                // 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
                if (dp[i][j] && j - i + 1 > maxLen) {
                    maxLen = j - i + 1;
                    begin = i;
                }
            }
        }
        return s.substring(begin, begin + maxLen);
    }
}

算法集锦(NO.4)高频习题_第5张图片
在这里插入图片描述
方法三:
“马拉车”算法(Manancher),该算法就是在字符串的每个字符之间插入‘#’然后字符串头部插入‘!’,字符串尾部插入‘?’这个!和?主要是用来起哨兵保护作用,并且左右边界的隔离作用。然后就可以忽略偶数长度的情况,直接考虑奇数的状态即可。最后计算长度时候忽略#。实际就是个优化的中心扩散。

class Solution {
    public String longestPalindrome(String s) {
        int start = 0, end = -1;
        StringBuffer t = new StringBuffer("#");
        for (int i = 0; i < s.length(); ++i) {
            t.append(s.charAt(i));
            t.append('#');
        }
        t.append('#');
        s = t.toString();

        List<Integer> arm_len = new ArrayList<Integer>();
        int right = -1, j = -1;
        for (int i = 0; i < s.length(); ++i) {
            int cur_arm_len;
            if (right >= i) {
                int i_sym = j * 2 - i;
                int min_arm_len = Math.min(arm_len.get(i_sym), right - i);
                cur_arm_len = expand(s, i - min_arm_len, i + min_arm_len);
            } else {
                cur_arm_len = expand(s, i, i);
            }
            arm_len.add(cur_arm_len);
            if (i + cur_arm_len > right) {
                j = i;
                right = i + cur_arm_len;
            }
            if (cur_arm_len * 2 + 1 > end - start) {
                start = i - cur_arm_len;
                end = i + cur_arm_len;
            }
        }

        StringBuffer ans = new StringBuffer();
        for (int i = start; i <= end; ++i) {
            if (s.charAt(i) != '#') {
                ans.append(s.charAt(i));
            }
        }
        return ans.toString();
    }

    public int expand(String s, int left, int right) {
        while (left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)) {
            --left;
            ++right;
        }
        return (right - left - 2) / 2;
    }
}

算法集锦(NO.4)高频习题_第6张图片
时间复杂度O(N),空间复杂度O(N)

反转每对括号间的子串
给出一个字符串 s(仅含有小写英文字母和括号)。

请你按照从括号内到外的顺序,逐层反转每对匹配括号中的字符串,并返回最终的结果。

注意,您的结果中 不应 包含任何括号。

示例 1:

输入:s = “(abcd)”
输出:“dcba”
示例 2:

输入:s = “(u(love)i)”
输出:“iloveu”
解释:先反转子字符串 “love” ,然后反转整个字符串。
示例 3:

输入:s = “(ed(et(oc))el)”
输出:“leetcode”
解释:先反转子字符串 “oc” ,接着反转 “etco” ,然后反转整个字符串。
示例 4:

输入:s = “a(bcdefghijkl(mno)p)q”
输出:“apmnolkjihgfedcbq”

提示:

0 <= s.length <= 2000
s 中只有小写英文字母和括号
题目测试用例确保所有括号都是成对出现的

方法一:
使用两个队列,将字符串中的字符一一放入结果栈中,当碰到‘)’,弹出结果队列尾部元素存放入辅助队列中,当结果队列弹出‘(’时候,将辅助队列的元素都返回至结果队列中。然后正向输出结果队列。

class Solution {
    public String reverseParentheses(String s) {
//使用双端队列deque当结果队列,因为作为结果队列需要考虑头尾双向输入输出
        Deque<String>queueEnd = new LinkedList<>();
        //作为辅助队列,只需要头部输出,尾部输入即可
        Queue<String>queueAssist = new LinkedList<>();
        //结果用str表示
        String str = "";
        for(int i=0;i<s.length();i++){
            if(s.charAt(i)!=')'){
            //character转换成string,尾部输入至queueEnd
                queueEnd.offer(String.valueOf(s.charAt(i)));
            }else {
            //当结果集遇到“)”时候,即可翻转直至遇到“(”
                while(!queueEnd.peekLast().equals("(")){
                    queueAssist.offer(queueEnd.pollLast());
                }
                //删除“(”
                queueEnd.pollLast();
                //将辅助队列的值放回结果队列中
                while(!queueAssist.isEmpty()){
                    queueEnd.offer(queueAssist.poll());
                }
            }
        }
        //使用string内部函数进行字符串拼接
        while(!queueEnd.isEmpty()){
            str+=queueEnd.poll();
        }
        return str;
    }
}

算法集锦(NO.4)高频习题_第7张图片
时间复杂度O(N^ 2),空间复杂度O(N)
空间优化方法:
此方法思路比较复杂,但是不管是时间还是空间优化都特别明显

class Solution {
    public String reverseParentheses(String s) {
        Deque<String> stack = new LinkedList<String>();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            if (ch == '(') {
            //stack存放()前的信息
                stack.push(sb.toString());
                //stringbuffer清除内容
                sb.setLength(0);
            } else if (ch == ')') {
            	//()内的内容进行反转
                sb.reverse();
                //将原来存储的插入到最前面
                sb.insert(0, stack.pop());
            } else {
                sb.append(ch);
            }
        }
        return sb.toString();
    }
}

算法集锦(NO.4)高频习题_第8张图片
算法集锦(NO.4)高频习题_第9张图片
方法二:

此方法借鉴leetcode方法二,思路十分不错,他在于将‘(’和‘)’之间的字符串切分,然后使用步长为1的step来进行左右翻转遍历。该思想步骤:
算法集锦(NO.4)高频习题_第10张图片

class Solution {
    public String reverseParentheses(String s) {
    //设置字符串s的长度
        int n = s.length();
        //建立辅助数组用来存放每个'('对应的‘)’来进行下标的存放。
        int[] pair = new int[n];
        //建立双端队列stack,进行存放括号相对应的下标
        Deque<Integer> stack = new LinkedList<Integer>();
        for (int i = 0; i < n; i++) {
        //如果遇到左括号,则stack来记录左括号的下标
            if (s.charAt(i) == '(') {
                stack.push(i);
                //遇到右下标,则在辅助数组中存放左右括号的下标,数组下标是左括号的话,他存放的就是右括号的下标。
            } else if (s.charAt(i) == ')') {
                int j = stack.pop();
                pair[i] = j;
                pair[j] = i;
            }
        }
//用Stringbuffer来进行字符串的拼接
        StringBuffer sb = new StringBuffer();
        //初始化起点0和步长1
        int index = 0, step = 1;
        while (index < n) {
            if (s.charAt(index) == '(' || s.charAt(index) == ')') {
        //进行分段读取下标
                index = pair[index];
                //如果完整左右括号内字符遍历完毕,则下跳换号。
                step = -step;
            } else {
                sb.append(s.charAt(index));
            }
            index += step;
        }
        return sb.toString();
    }
}

算法集锦(NO.4)高频习题_第11张图片

算法集锦(NO.4)高频习题_第12张图片

你可能感兴趣的:(高频题目,算法)