leetcode刷题

leetcode刷题


5.最长回文子串

  • 给你一个字符串 s,找到 s 中最长的回文子串。
    原题链接
class Solution {
    public String longestPalindrome(String s) {
        if(s.length() == 1 || s.length() == 0){
            return s;
        }

        int end = 0,start = 0;
        for (int i = 0; i < s.length() ; i++) {
            //奇数对称
            int len1 = expandCenter(s,i,i);
            //偶数对称
            int len2 = expandCenter(s,i,i+1);
            //取最大值
            int len = Math.max(len1,len2);
            //如果新的回文字符串长度大于之前的回文字符串长度,更新字符串的start和end
            if(len > end - start){
                start = i - (len - 1)/2;
                end = i + len/2;
            }
        }
        //所取区间[start,end]
        return s.substring(start,end+1);
    }

    //计算回文串长度
    private int expandCenter(String s,int right,int left){
        while(left >= 0 && right < s.length() && s.charAt(right) == s.charAt(left)){
            right++;
            left--;
        }
        return right - left - 1;
    }


}

11. 盛最多水的容器

给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
原题链接

class Solution {
    public int maxArea(int[] height) {
        int startI = 0,endI = height.length -1;
        int num[] = new int[height.length];
        int i = 0;
        while (startI < endI){
             num[i] = Math.min(height[startI],height[endI]) * (endI-startI);
             if(height[startI] < height[endI]){
                 startI++;
             }else{
                 endI--;
             }
             i++;
        }
        int max = num[0];
        for (int j = 1; j < num.length; j++) {
            if(num[j] > max){
                max = num[j];
            }
        }
        return max;
    }

}

回文数

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

  • 时间复杂度为log n
class Solution {
    public boolean isPalindrome(int x) {
        // 特殊情况:
        // 如上所述,当 x < 0 时,x 不是回文数。
        // 同样地,如果数字的最后一位是 0,为了使该数字为回文,
        // 则其第一位数字也应该是 0
        // 只有 0 满足这一属性
        if (x < 0 || (x % 10 == 0 && x != 0)) {
            return false;
        }

        int revertedNumber = 0;
        while (x > revertedNumber) {
            revertedNumber = revertedNumber * 10 + x % 10;
            x /= 10;
        }

        // 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
        // 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
        // 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
        return x == revertedNumber || x == revertedNumber / 10;
    }
}

6、 Z 字形变换

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:

P A H N
A P L S I I G
Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。

class Solution {
    public String convert(String s, int numRows) {
        if(numRows == 1){
            return s;
        }
        //表示第几行
        StringBuilder builder[] = new StringBuilder[numRows];
        for (int i = 0; i < builder.length ; i++) {
               builder[i] = new StringBuilder(10);
        }
        int col = numRows +  numRows - 2;
        char ca[] = s.toCharArray();
        for (int i = 0; i < s.length() ; i++) {
            int k = i % col;
            if(k < numRows){
                //Z字形的一竖
                builder[k].append(ca[i]);
            }else{
                 //Z字形的斜线
                 int l = numRows-(k - numRows) - 2;
                 builder[l].append(ca[i]);
            }

        }
        StringBuilder ss = builder[0];
        for (int i = 1; i < builder.length; i++) {
            ss.append(builder[i]);
        }
        return  ss.toString();
    }
}

原题链接

###15. 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
         if(nums.length < 3){
             return Collections.emptyList();
         }
         List<List<Integer>> ans = new ArrayList<>();
         int len = nums.length;
         Arrays.sort(nums);
        for (int i = 0; i < len; i++) {
            if(nums[i] > 0) break;
            if(i > 0 && nums[i] == nums[i-1]) continue;
            int L = i + 1;
            int R = len - 1;
            while (L < R){
                int sum = nums[i] + nums[L] + nums[R];
                if(sum == 0){
                    ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
                    while (L < R && nums[L] == nums[L+1]) L++;
                    while (L < R && nums[R] == nums[R-1]) R--;
                    L++;
                    R--;
                }else if( sum < 0){
                    L++;
                }else{
                    R--;
                }
            }
        }
       return ans;
    }
}

原题链接

12. 整数转罗马数字

罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

字符          数值
I             1
V             5
X             10
L             50
C             100
D             500
M             1000

例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。

通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个整数,将其转为罗马数字。输入确保在 1 到 3999 的范围内。

//法一:自己写的真菜
class Solution {
    public String intToRoman(int num) {
        int x = num;
        List<Integer> list = new ArrayList<>();
        String s = "";
        int cout = 0;
        while(x != 0){
            int i = x % 10;
            if(cout == 0){
                if(i > 0 && i < 4){
                    for (int j = i; j > 0 ; j--) {
                        s = "I" + s;
                    }
                }
                if(i > 4 && i < 9){

                    for (int j = i; j > 5 ; j--) {
                        s = "I"+ s;
                    }
                    s = "V" + s;
                }
                if(i == 4){
                    s = "IV" + s;
                }
                if(i == 9){
                    s = "IX" + s;
                }

            }else if(cout == 1){
                if(i > 0 && i < 4){
                    for (int j = i; j > 0 ; j--) {
                        s = "X" + s;
                    }
                }
                if(i > 4 && i < 9){
                    for (int j = i; j > 5 ; j--) {
                        s = "X" + s;
                    }
                    s = "L" + s;
                }
                if(i == 4){
                    s = "XL" + s;
                }
                if(i == 9){
                    s = "XC" + s;
                }
            }else if(cout == 2){
                if(i > 0 && i < 4){
                    for (int j = i; j > 0 ; j--) {
                        s = "C" + s;
                    }
                }
                if(i > 4 && i < 9){
                    for (int j = i; j > 5 ; j--) {
                        s = "C" + s;
                    }
                    s = "D" + s;
                }
                if(i == 4){
                    s = "CD" + s;
                }
                if(i == 9){
                    s = "CM" + s;
                }
            }else{
                for (int j = 0; j < i ; j++) {
                    s = "M" + s;
                }
            }
            cout++;
            x /= 10;
        }
        return s;
    }
   
}

//法二:大神写的
public String intToRoman(int num) {
    
    String[] thousands = {"", "M", "MM", "MMM"};
    String[] hundreds = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; 
    String[] tens = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
    String[] ones = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
    
    return thousands[num / 1000] + hundreds[num % 1000 / 100] + tens[num % 100 / 10] + ones[num % 10];
}

原题链接

17. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

题目

class Solution {
    public List<String> letterCombinations(String digits) {
        Map<Character,String[]> map = new HashMap<>();
        Queue<String> queue = new LinkedList<>();
        map.put('2',new String[]{"a","b","c"});
        map.put('3',new String[]{"d","e","f"});
        map.put('4',new String[]{"g","h","i"});
        map.put('5',new String[]{"j","k","l"});
        map.put('6',new String[]{"m","n","o"});
        map.put('7',new String[]{"p","q","r","s"});
        map.put('8',new String[]{"t","u","v"});
        map.put('9',new String[]{"w","x","y","z"});
        char ca[] = digits.toCharArray();

        for (int i = 0; i < ca.length ; i++) {
             if(map.containsKey(ca[i])){
                 String str[] = map.get(ca[i]);
                 if(queue.isEmpty()){
                     for (int j = 0; j < str.length; j++) {
                         queue.offer(str[j]);
                     }
                 }else{

                         String tempStr = queue.element();
                         int len = tempStr.length();
                         while (queue.element().length() == len){
                             tempStr = queue.poll();
                             for (int j = 0; j < str.length ; j++) {
                                 queue.offer(tempStr+str[j]);
                             }
                            // System.out.println(queue.toString());
                         }

                 }



             }
        }
        return (List)queue;
    }
  
}

20. 有效的括号

给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。

//解法一
class Solution {
    public boolean isValid(String s) {
        while(s.contains("()")||s.contains("[]")||s.contains("{}")){
            if(s.contains("()")){
                s=s.replace("()","");
            }
            if(s.contains("{}")){
                s=s.replace("{}","");
            }
            if(s.contains("[]")){
                s=s.replace("[]","");
            }
        }
        return s.length()==0;
    }
}
//解法二
class Solution {
    public boolean isValid(String s) {
       Map<Character,Character> map = new HashMap<>();
       map.put(')','(');
       map.put(']','[');
       map.put('}','{');
       char ca[] = s.toCharArray();
       int len = ca.length;
       if(len % 2 == 1){
           return false;
       }
       Deque<Character> stack = new LinkedList<>();
        for (int i = 0; i < len ; i++) {
            if(map.containsKey(ca[i])){
                if(stack.isEmpty() || stack.peek() != map.get(ca[i])){
                    return false;
                }
                stack.pop();
            }else{
                stack.push(ca[i]);
            }
        }
        return stack.isEmpty();
    }
}

原题链接

21. 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。

//思路:用新建一个链表,比较l1和l2元素的大小,谁小就移动这个数
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 l1, ListNode l2) {
         ListNode head  = new ListNode(0);
         ListNode cur = head;
         while (l1 != null && l2 != null){
             if(l1.val <= l2.val){
                cur.next = l1;
                cur = cur.next;
                l1 = l1.next;
             }else{
                cur.next = l2;
                cur = cur.next;
                l2 = l2.next;
             }
         }
         if (l1 == null){
             cur.next = l2;
         }else{
             cur.next = l1;
         }
         return head.next;

    }
}

22. 括号生成

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:

输入:n = 1
输出:["()"]

### 思路1:
当我们清楚所有 i<n 时括号的可能生成排列后,对与 i=n 的情况,我们考虑整个括号排列中最左边的括号。
它一定是一个左括号,那么它可以和它对应的右括号组成一组完整的括号 "( )",我们认为这一组是相比 n-1 增加进来的括号。

那么,剩下 n-1 组括号有可能在哪呢?

剩下的括号要么在这一组新增的括号内部,要么在这一组新增括号的外部(右侧)。

class Solution {
    public List<String> generateParenthesis(int n) {
       LinkedList<LinkedList<String>> res = new LinkedList<>();
       LinkedList<String> list0 = new LinkedList<>();
       list0.add("");
       res.add(list0);
       //特殊情况
        if(n == 0){
            return res.get(0);
        }
       LinkedList<String> list1 = new LinkedList<>();
       list1.add("()");
       res.add(list1);
        for (int i = 2; i <= n ; i++) {
            LinkedList<String> temp = new LinkedList<>();
            for (int j = 0; j < i ; j++) {
            //遍历两种情况
                List<String> str1 = res.get(j);
                List<String> str2 = res.get(i-1-j);
                for (String s1:str1) {
                    for (String s2:str2) {
                        String e1 = "(" + s1 + ")" + s2;
                        temp.add(e1);
                    }
                }
            }
            res.add(temp);
        }
        return res.get(n);
    }
}

//大佬思路,妙
class Solution {
    public List<String> generateParenthesis(int n) {
        List<String> res = new ArrayList<String>();
        generate(res, "", 0, 0, n);

        return res;
    }
    //count1统计“(”的个数,count2统计“)”的个数
    public void generate(List<String> res , String ans, int count1, int count2, int n){
       //递归出口
        if(count1 > n || count2 > n) return;

        if(count1 == n && count2 == n)  res.add(ans);


        if(count1 >= count2){
            String ans1 = new String(ans);
            generate(res, ans+"(", count1+1, count2, n);
            generate(res, ans1+")", count1, count2+1, n);

        }
        //System.out.println(res.toString());
    }


}

原题链接

23. 合并K个升序链表

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

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 mergeKLists(ListNode[] lists) {
        if(lists == null){
            return null;
        }
        int count = 0;
        for (int i = 0; i < lists.length ; i++) {
            if(lists[i] != null){
                break;
            }
            count++;
        }
        if(count == lists.length){
            return null;
        }
        for (int i = 0; i < lists.length - 1; i++) {
           lists[i+1] = mergeTwoLists(lists[i],lists[i+1]);
        }
        return lists[lists.length-1];
    }
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
         ListNode head  = new ListNode(0);
         ListNode cur = head;
         while (l1 != null && l2 != null){
             if(l1.val <= l2.val){
                cur.next = l1;
                cur = cur.next;
                l1 = l1.next;
             }else{
                cur.next = l2;
                cur = cur.next;
                l2 = l2.next;
             }
         }
         if (l1 == null){
             cur.next = l2;
         }else{
             cur.next = l1;
         }
         return head.next;

    }
}

原题链接

31. 下一个排列

实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。

如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。

必须 原地 修改,只允许使用额外常数空间。

思路:参考

class Solution {
    public void nextPermutation(int[] nums) {
       if(nums.length <= 1){
           return;
       }
     int len = nums.length;
       int index1=0,index2 = 1;
       int flag = 0;
        for (int i = len - 1; i > 0 ; i--) {
           if(nums[i] > nums[i-1]){
               index1 = i-1;
               index2 = i;
               flag = 1;
               break;
           }
        }
        if(flag == 1){
            for (int i = len - 1; i >= index2; i--) {
                if(nums[index1] < nums[i]){
                    int temp = nums[i];
                    nums[i] = nums[index1];
                    nums[index1] = temp;
                    //[.....)
                    Arrays.sort(nums,index2,len);
                    return;
                }
            }
        }else{
            int j = len - 1;
            for (int i = 0; i <= j; i++) {
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
                j--;
            }
        }

    }

}

原题链接

32. 最长有效括号

给你一个只包含 ‘(’ 和 ‘)’ 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

思路参考:第一条评论

class Solution {
    //存储结果的类结构
    static class Team{
        private int index;
        private char value;

        Team(int index,char value){
            this.index = index;
            this.value = value;
        }
        public char getValue() {
            return value;
        }

        public int getIndex() {
            return index;
        }

    }
    public static int longestValidParentheses(String s) {
       LinkedList<Team> queue = new LinkedList<>();
       char ca[] = s.toCharArray();
       int len = ca.length;
       boolean trueOrFalse[] = new boolean[len];
       //结果数组
        for (int i = 0; i < len; i++) {
            trueOrFalse[i] = false;
        }
       if(len <= 1){
           return 0;
       }
       
       //模拟栈
        for (int i = 0; i < len; i++) {
            if(!queue.isEmpty()){
                if (queue.element().getValue() == '(' && ca[i] == ')'){
                    trueOrFalse[i] = true;
                    trueOrFalse[queue.element().getIndex()] = true;
                    queue.pollFirst();
                    continue;
                }
            }
            queue.addFirst(new Team(i,ca[i]));
        }

        //寻找连续个true的数组元素的长度
        int bestLen = 0;
        int tryLen = 0;
        for (int i = 0; i <len ; i++) {
            if (trueOrFalse[i]){
                tryLen++;
                if(tryLen > bestLen){
                    bestLen = tryLen;
                }
            }else{
                tryLen = 0;
            }
        }
        return bestLen;
    }
 
}

33. 搜索旋转排序数组

升序排列的整数数组 nums 在预先未知的某个点上进行了旋转(例如, [0,1,2,4,5,6,7] 经旋转后可能变为 [4,5,6,7,0,1,2] )。

请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。
注意:时间复杂度要求logn

  • 思路:二分查找(官方题解)
class Solution {
    public int search(int[] nums, int target) {
       return search(nums,target,0,nums.length-1);
    }
    public int search(int[] nums, int target,int startIndex,int endIndex) {
        int midIndex = (startIndex + endIndex) / 2;
        int leftStart = startIndex;
        //防止溢出
        int leftEnd = midIndex - 1 < startIndex ? startIndex : midIndex-1;
        int rightStart = midIndex + 1 > endIndex ? endIndex : midIndex+1;
        int rightEnd = endIndex;
        //跳出条件
        if(nums[midIndex] == target){
            return midIndex;
        }
        if(startIndex == endIndex && nums[midIndex] != target){
            return -1;
        }
        //二分查找子数组
        if(nums[leftStart] <= nums[leftEnd] ){
            if(target >= nums[leftStart] && target <= nums[leftEnd]){
                return search(nums,target,leftStart,leftEnd);
            }else{
                return search(nums,target,rightStart,rightEnd);
            }
        }else{
            if(target >= nums[rightStart] && target <= nums[rightEnd]){
                return search(nums,target,rightStart,rightEnd);
            }else{
                return search(nums,target,leftStart,leftEnd);
            }
        }

    }
   

}

原题链接

34. 在排序数组中查找元素的第一个和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。
注:要求使用logn时间复杂度的算法

  • 思路:先用二分查找,若找到等于target元素的数组值,在从这个下标向左向右移动,直到其元素不等于target;若没有找到,就返回【-1,-1】
class Solution {
    public int[] searchRange(int[] nums, int target) {
       return searchRange(nums,target,0,nums.length-1);
    }
    public int[] searchRange(int[] nums,int target,int startIndex,int endIndex){
        int midIndex = (startIndex + endIndex) / 2;
        //数组为空,返回【-1,-1】
        if(nums.length == 0){
            return new int[]{-1,-1};
        }
        //未查找到,返回【-1,-1】
        if(startIndex == endIndex && nums[midIndex] != target){
            return new int[]{-1,-1};
        }
        if(nums[midIndex] == target){
            int index1 = midIndex;
            int index2 = midIndex;
            //防止index1越界
            while (index1-1 >= 0){
                if(nums[index1-1] == target){
                    index1--;
                }else{
                    break;
                }
            }
            //防止index2越界
            while (index2+1 <= nums.length-1){
                if(nums[index2+1] == target){
                    index2++;
                }else{
                    break;
                }
            }
            return new int[]{index1,index2};
        }else if(nums[midIndex] > target){
            //防止溢出,二分查找子数组
            if(midIndex-1 >= startIndex){
                return searchRange(nums,target,startIndex,midIndex-1);
            }else{
                return searchRange(nums,target,startIndex,startIndex);
            }
        }else{
            //防止溢出,二分查找子数组
            if(midIndex+1 <= endIndex){
                return searchRange(nums,target,midIndex+1,endIndex);
            }else{
                return searchRange(nums,target,endIndex,endIndex);
            }

        }

    }
   
}

原题链接

39. 组合总和

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。

思路:回溯算法,dfs,递归算法

未减枝:

class Solution {
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res = new LinkedList<>();
        List<Integer> combine = new LinkedList<>();
        if(candidates.length == 0){
            return res;
        }
        dfs(res,combine,target,candidates,0);
        return res;
    }
    public void dfs(List<List<Integer>> res,List<Integer> combine,int target,int[] candidates,int index){
           /是否还可以向右
           if(index == candidates.length){
               return;
           }
            //满足条件
           if(target == 0){
               res.add(new LinkedList<>(combine));
               return;
           }
           //往右
           dfs(res, combine, target, candidates, index+1);
           //判断是否还可以向下
           if(target - candidates[index] >= 0){
               combine.add(candidates[index]);
               //往下
               dfs(res,combine,target-candidates[index],candidates,index);
               combine.remove(combine.size()-1);
           }

    }
}

减枝:

class Solution{
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList<>();
        if (candidates.length == 0) {
            return res;
        }

        // 排序是剪枝的前提,必须先进行排序
        Arrays.sort(candidates);

        List<Integer> path = new LinkedList<>();
        dfs(candidates, 0, target, path, res);
        return res;
    }
    public void dfs(int[] candidates,int index,int target,List<Integer> path,List<List<Integer>> res){
        if(index == candidates.length){
            return;
        }
        if(target == 0){
            res.add(new LinkedList<>(path));
            return;
        }
        //避免重复解
        for (int i = index; i < candidates.length ; i++) {
            //减枝
            if(target - candidates[i] < 0){
                break;
            }
            path.add(candidates[i]);
            dfs(candidates, i, target-candidates[i], path, res);
            path.remove(path.size()-1);
        }
    }
}

原题链接

739. 每日温度

请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。

例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。

提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。

  • 思路:单调栈,应用栈的数据结构实现。
  • 大佬思路(秒呀!):大佬思路
class Solution {
    public int[] dailyTemperatures(int[] T) {
        //代表栈
        LinkedList<Integer> teamList = new LinkedList<>();
        int answers[] = new int[T.length];
        //初始化数组
        for (int i = 0; i < answers.length ; i++) {
            answers[i] = 0;
        }
        //一次遍历
        for (int i = 0; i < T.length; i++) {
            int temp = T[i];
            //单调栈
            while (!teamList.isEmpty() && temp > T[teamList.peek()]){
                int preIndex = teamList.pop();
                answers[preIndex] = i - preIndex;
            }

            teamList.push(i);
            System.out.println(teamList.toString());
        }
        return answers;
    }
}

原题链接

42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:
图示
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。

class Solution {
    public int trap(int[] height) {
        if (height.length==0){
            return 0;
        }
        int len = height.length;
       int left_max[] = new int[len];
       int right_max[] = new int[len];
       int ans = 0;
       left_max[0] = height[0];
        for (int i = 1; i < len ; i++) {
            left_max[i] = Math.max(left_max[i-1],height[i]);
        }
        right_max[len-1] = height[len-1];
        for (int i = len - 2; i >=0 ; i--) {
            right_max[i] = Math.max(right_max[i+1],height[i]);
        }
        for (int i = 0; i < len ; i++) {
            int one = Math.min(left_max[i],right_max[i]) - height[i];
            ans += one;
        }
        return ans;
    }
}

46. 全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

输入: [1,2,3]
输出:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]
  • key:回溯算法dfs
class Solution {
    public List<List<Integer>> permute(int[] nums) {
       List<List<Integer>> answers = new ArrayList<>();
       Deque<Integer> path = new ArrayDeque<>();
       int len = nums.length;
       boolean []used = new boolean[len];
       //数字个数为零时
       if(len == 0){
           return answers;
       }
       //dfs入口
       dfs(nums,len,answers,path,0,used);
       return answers;
    }
    public void dfs(int []nums,int len,List<List<Integer>> answers,Deque<Integer> path,int count,boolean []used){
    //递归出口,当生成一个path后,used数组全为true
        if(count == len){
            answers.add(new ArrayList<>(path));
            return;
        }
        //循环遍历,将未用过的值加入path
        for (int i = 0; i < len; i++) {
            if(!used[i]){
                path.addFirst(nums[i]);
                used[i] = true;
                dfs(nums,len,answers,path,count+1,used);
                //回溯
                path.removeFirst();
                used[i] = false;
            }
        }
    }
}

原题链接

48. 旋转图像

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

示例 1:

在这里插入图片描述

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]

//先转置,再对称变换
class Solution {
    public void rotate(int[][] matrix) {
        int n = matrix.length;
        //上半角,置换下半角(转置)
        for (int i = 0; i < n-1; i++) {
            for (int j = i+1; j < n ; j++) {
                 int temp = matrix[i][j];
                 matrix[i][j] = matrix[j][i];
                 matrix[j][i] = temp;
            }
        }

        for (int i = 0; i < matrix.length ; i++) {
            int left = 0;
            int right = matrix[i].length - 1;
            while (left <= right){
                int temp = matrix[i][left];
                matrix[i][left] = matrix[i][right];
                matrix[i][right] = temp;
                left++;
                right--;
            }
        }
    }
}

原题链接

647. 回文子串

给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。

具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。

示例 1:

输入:"abc"
输出:3
解释:三个回文子串: "a", "b", "c"

大佬思路
解一(动态规划):

class Solution {
    public int countSubstrings(String s) {
        int len = s.length();
         boolean [][]dp = new boolean[len][len];
         int ans = 0;
        for (int i = 0; i < len; i++) {
            for (int j = 0; j <= i ; j++) {
                if(s.charAt(i) == s.charAt(j) &&(i-j < 2 || dp[j+1][i-1])){
                    dp[j][i] = true;
                    ans++;
                }
            }
        }
        return ans;
    }
  
}

解二(中心点算法):

//647. 回文子串
class Solution {
    public int countSubstrings(String s) {
         int count = 0;
         int len = s.length();
        for (int i = 0; i < len; i++) {
            count += numAdd(i,i,s,len);
            count += numAdd(i,i+1,s,len);
        }
        return count;
    }
    public int numAdd(int left,int right,String s,int len){
        int count = 0;
        while (left >= 0 && right < len && s.charAt(left) == s.charAt(right)){
            count++;
            left--;
            right++;
        }
        return count;
    }
  stem.out.println(solution.countSubstrings("aaa"));
    }
}

原题链接

49. 字母异位词分组

给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。

示例:

输入: ["eat", "tea", "tan", "ate", "nat", "bat"]
输出:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]

思路:利用一个map,将字符串排序结果作为key,字符串添加到list里面,将map的value作为返回的结果。

class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String,List<String>> map = new HashMap<>();
        int len = strs.length;
        if (len == 0){
            return null;
        }
        for (int i = 0; i < len; i++) {
            char []ca = strs[i].toCharArray();
            Arrays.sort(ca);
            String key = String.valueOf(ca);
            //太过冗杂
//            if(!map.containsKey(key)){
//                List<String> list = new ArrayList<>();
//                list.add(strs[i]);
//                map.put(key,list);
//            }else{
//                List<String> list = map.get(key);
//                list.add(strs[i]);
//                map.put(key,list);
//            }
            List<String> list = map.getOrDefault(key,new ArrayList<String>());
            list.add(strs[i]);
            map.put(key,list);
        }
        return new ArrayList<>(map.values());
    }
}

原题链接

53. 最大子序和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

参考☞
key:动态规划,贪心算法

class Solution {
    public int maxSubArray(int[] nums) {
       int sum = 0;
       int len = nums.length;
       int max = nums[0];
        for (int i = 0; i < len; i++) {
             if(sum > 0){
                 sum += nums[i];
             }else{
                 //sum <= 0,从该数开始重新计数
                 sum = nums[i];
             }
             max = Math.max(max,sum);
        }
        return max;
    }
}

原题链接

55. 跳跃游戏

给定一个非负整数数组 nums ,你最初位于数组的 第一个下标 。
数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标。

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。
/*
思路启发:
想象你是那个在格子上行走的小人,格子里面的数字代表“能量”,你需要“能量”才能继续行走。
每次走到一个格子的时候,你检查现在格子里面的“能量”和你自己拥有的“能量”哪个更大,取更大的“能量”! 如果你有更多的能量,你就可以走的更远啦!~
 */
class Solution {
    public boolean canJump(int[] nums) {
       int len = nums.length;
       if (len == 1){
           return true;
       }
       int maxIndex = 0;
        for (int i = 0; i < len - 1; i++) {
            if(maxIndex < i){
                return false;
            }
            maxIndex = Math.max(maxIndex,nums[i]+i);
            if(maxIndex >= len - 1){
              return true;
            }
        }
        return false;
    }
   
}
  • 动态规划解法:dp[i] = max(dp[i-1],i+nums[i]);
class Solution {
    public boolean canJump(int[] nums) {
        int len = nums.length;
        int en = nums[0];
        int  i=0;
        while (i != len-1 && en != 0) {
            en--;
            i++;
            if(en < nums[i]){
                en = nums[i];
            }
        }
        if(en == 0 && i != len-1){
            return false;
        }
        return true;
    }
}

原题链接

56. 合并区间

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间。

class Solution {
    public int[][] merge(int[][] intervals) {
        int len = intervals.length;
        if(len == 0 || len == 1){
            return intervals;
        }
        //将同一start排在一起
        Arrays.sort(intervals, new Comparator<int[]>() {
            @Override
            public int compare(int[] intervals1, int[] intervals2) {
                 return intervals1[0] - intervals2[0];
            }
        });
        List<int[]> merged = new ArrayList<int[]>();
        int start = intervals[0][0];
        int end = intervals[0][28];
        for (int i = 1; i < len; i++) {
            if(start == intervals[i][0]){
                end = intervals[i][29] > end ? intervals[i][30] : end;
            }else if(start < intervals[i][0] && end  >= intervals[i][0] && end < intervals[i][31]){
                end = intervals[i][32];
            }else if(intervals[i][0] > end){
                int []kk = new int[2];
                kk[0] = start;
                kk[1] = end;
                merged.add(kk);
                start = intervals[i][0];
                end = intervals[i][33];
            }
            //最后一个的处理
            if(i == len - 1){
                int []kk = new int[2];
                kk[0] = start;
                kk[1] = end;
                merged.add(kk);
            }
        }
        return merged.toArray(new int[merged.size()][34]);
    }
}

原题链接

62. 不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

示例 1:
输入:m = 3, n = 7
输出:28

动态规划转移方程
key:动态规划(下一个状态受之前的状态的影响)

class Solution {
    public int uniquePaths(int m, int n) {
       int [][]dp = new int[m][n];
        for (int i = 0; i < m; i++) {
            dp[i][0] = 1;
        }
        for (int i = 0; i < n ; i++) {
            dp[0][i] = 1;
        }
        for (int i = 1; i < m ; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }
        return dp[m-1][n-1];
    }
}

原题链接

64. 最小路径和

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

在这里插入图片描述

示例 1:
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。

类似于62. 不同路径,都是动态规划

class Solution {
    public int minPathSum(int[][] grid) {
        int col_len = grid.length;
        int row_len = grid[0].length;
        int [][]dp = new int[col_len][row_len];
        dp[0][0] = grid[0][0];
        for (int i = 1; i < col_len ; i++) {
            dp[i][0] = grid[i][0] + dp[i-1][0];
        }
        for (int i = 1; i < row_len; i++) {
            dp[0][i] = grid[0][i] + dp[0][i-1];
        }
        for (int i = 1; i < col_len; i++) {
            for (int j = 1; j < row_len; j++) {
                dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1]) + grid[i][j];
            }
        }
        return dp[col_len-1][row_len-1];
    }
  
}

原题链接

70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。

示例 1:
输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

key:动态规划
代码:

class Solution {
    public int climbStairs(int n) {
        if(n == 1 || n == 2){
            return n;
        }
       int []dp = new int[n+1];
       dp[1] = 1;
       dp[2] = 2;
        for (int i = 3; i <= n ; i++) {
            dp[i] = dp[i-1] + dp[i-2];
        }
        return dp[n];
    }
}
//减小空间复杂度(法二)
class Solution {
  
    public int climbStairs(int n) {
        if(n == 1){
            return 1;
        }
        int first = 1;
        int second = 2;
        for (int i = 3; i <= n ; i++) {
            int third = first + second;
            first = second;
            second = third;
        }
        return second;
    }
    
}

原题链接

72. 编辑距离

给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符

示例 1:
输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

key:动态规划

class Solution {
    public int minDistance(String word1, String word2) {
        int col_len = word1.length();
        int row_len = word2.length();
        char []startWords = word1.toCharArray();
        char []endWords = word2.toCharArray();
        int [][]dp = new int[col_len+1][row_len+1];
        dp[0][0] = 0;
        for (int i = 1; i <= col_len; i++) {
            dp[i][0] = i;
        }
        for (int i = 1; i <= row_len ; i++) {
            dp[0][i] = i;
        }
        for (int i = 1; i <= col_len ; i++) {
            for (int j = 1; j <= row_len ; j++) {
                dp[i][j] = 1 + ( Math.min(dp[i][j-1],dp[i-1][j]) > dp[i-1][j-1] ? dp[i-1][j-1] :  Math.min(dp[i][j-1],dp[i-1][j]) );
                //words数组比dp数组小1
                if(startWords[i-1] == endWords[j-1]){
                    dp[i][j] = dp[i-1][j-1];
                }
            }
        }
        return dp[col_len][row_len];
    }
}

动态规划

原题链接

75. 颜色分类

给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

示例 1:
输入:nums = [2,0,2,1,1,0]
输出:[0,0,1,1,2,2]
class Solution {
    public void sortColors(int[] nums) {
        int len = nums.length;
        int start = 0;
        for (int i = 0; i < len ; i++) {
            if (nums[i] == 0){
                if(start != i){
                    swap(nums,start,i);
                }
                start++;
            }
        }
        if(start < len){
            for (int i = 0; i < len ; i++) {
                if (nums[i] == 1){
                    if(start != i){
                        swap(nums,start,i);
                    }
                    start++;
                }
            }
        }

    }
    public void swap(int []nums,int index1,int index2){
        int temp = nums[index1];
        nums[index1] = nums[index2];
        nums[index2] = temp;
    }
}

原题链接

76. 最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"

思路参考:点这里

class Solution {
    public String minWindow(String s, String t) {
        int start = 0,end = 0;
        int k_start = -1,k_end = -1;
        Map<Character,Integer> sMap = new HashMap<>();
        Map<Character,Integer> tMap = new HashMap<>();
        char []sChar = s.toCharArray();
        char []tChar = t.toCharArray();
        for (int i = 0; i < tChar.length ; i++) {
            char c = tChar[i];
            tMap.put(c,tMap.getOrDefault(c,0) + 1);
        }
        while (end < s.length()){
            char c = sChar[end];
            sMap.put(c,sMap.getOrDefault(c,0) + 1);
            while (check(sMap,tMap) && start <= end){
                if(k_end == -1){
                    k_end = end;
                    k_start = start;
                }
                if(end - start < k_end - k_start){
                    k_end = end;
                    k_start = start;
                }
               sMap.put(sChar[start],sMap.get(sChar[start]) - 1);
               start++;
            }
            end++;

        }
        return k_start == -1 ? "" : s.substring(k_start,k_end+1);
    }
    public boolean check(Map<Character,Integer> map1,Map<Character,Integer> map2){
        for (char key : map2.keySet()) {
            if(!map1.containsKey(key) || map1.get(key) < map2.get(key) ){
               return false;
            }
        }
        return true;
    }
    
}

原题链接

78. 子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

需要重点理解,回溯算法和dfs

class Solution {
    public List<List<Integer>> subsets(int[] nums) {
       List<Integer> list = new ArrayList<>();
       List<List<Integer>> lists = new ArrayList<>();
       int len = nums.length;
       dfs(0,nums,list,lists,len);
       return lists;
    }
    public void dfs(int i,int []nums,List<Integer> list,List<List<Integer>> lists,int len){
        if(i == len){
            lists.add(new ArrayList<>(list));
            return;
        }
        list.add(nums[i]);
        dfs(i+1,nums,list,lists,len);
        list.remove(list.size() -1);
        dfs(i+1,nums,list,lists,len);
    }

}

原题链接

371. 两整数之和

不使用运算符 + 和 - ​​​​​​​,计算两整数 ​​​​​​​a 、b ​​​​​​​之和。
思路参考:点这里

示例 1:
输入: a = 1, b = 2
输出: 3
class Solution {
public:
    int getSum(int a, int b) {
        while (b != 0){
            int c = (unsigned int)(a&b) << 1;
            a = a ^ b;
            b = c;
        }
        return a;
    }

};

原题链接

1015 德才论 (25 分)

来源于:PAT乙级
宋代史学家司马光在《资治通鉴》中有一段著名的“德才论”:“是故才德全尽谓之圣人,才德兼亡谓之愚人,德胜才谓之君子,才胜德谓之小人。凡取人之术,苟不得圣人,君子而与之,与其得小人,不若得愚人。”

现给出一批考生的德才分数,请根据司马光的理论给出录取排名。

输入格式:
输入第一行给出 3 个正整数,分别为:N(≤10^5),即考生总数;L(≥60),为录取最低分数线,即德分和才分均不低于 L 的考生才有资格被考虑录取;H(<100),为优先录取线——德分和才分均不低于此线的被定义为“才德全尽”,此类考生按德才总分从高到低排序;才分不到但德分到线的一类考生属于“德胜才”,也按总分排序,但排在第一类考生之后;德才分均低于H,但是德分不低于才分的考生属于“才德兼亡”但尚有“德胜才”者,按总分排序,但排在第二类考生之后;其他达到最低线的考生也按总分排序,但排在第三类考生之后。
随后 N 行,每行给出一位考生的信息,包括:准考证号 德分 才分,其中准考证号为 8 位整数,德才分为区间 [0, 100] 内的整数。数字间以空格分隔。

输出格式:
输出第一行首先给出达到最低分数线的考生人数 M,随后 M 行,每行按照输入格式输出一位考生的信息,考生按输入中说明的规则从高到低排序。当某类考生中有多人总分相同时,按其德分降序排列;若德分也并列,则按准考证号的升序输出。
原题链接
key:快排

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct Student{
    int num;
    int dScore;
    int cScore;
    int flag;
};
int comp(struct Student s1,struct Student s2){
    // if s1 > s2 return 1
    // else return 0;
    if(s1.cScore+s1.dScore > s2.cScore+s2.dScore){
        return 1;
    }else if(s1.cScore+s1.dScore == s2.cScore+s2.dScore){
        if(s1.dScore > s2.dScore){
            return 1;
        }else if(s1.dScore == s2.dScore){
            if(s1.num < s2.num){
                return 1;
            }
        }
    }
    return 0;

}
int findPos(struct Student *stu,int i,int j){
    struct Student temp;
    temp.cScore = stu[i].cScore;
    temp.dScore = stu[i].dScore;
    temp.num = stu[i].num;
    while(i<j){
        while(i<j && (comp(stu[j],temp) == 0)){
            j--;
        }
        if(i<j){
            stu[i].cScore = stu[j].cScore;
            stu[i].dScore = stu[j].dScore;
            stu[i].num = stu[j].num;
            i++;
        }
        while(i<j && (comp(stu[i],temp) == 1)){
            i++;
        }
        if(i<j){
            stu[j].cScore = stu[i].cScore;
            stu[j].dScore = stu[i].dScore;
            stu[j].num = stu[i].num;
            j--;
        }
    }
    stu[i].cScore = temp.cScore;
    stu[i].dScore = temp.dScore;
    stu[i].num = temp.num;
    return i;


}
void quickSort(struct Student *stu,int l,int r){
    if(stu == NULL) return;
    if(l < r){
        int k = findPos(stu,l,r);
        quickSort(stu,l,k-1);
        quickSort(stu,k+1,r);
    }
}
int main(int argc, char *argv[]) {

    int n,low,high;
    int i;
    int count = 0;
    scanf("%d %d %d",&n,&low,&high);
    struct Student stu[n];
    struct Student temp[n];
    for(i=0;i<n;i++){
        scanf("%d %d %d",&stu[i].num,&stu[i].dScore,&stu[i].cScore);
        stu[i].flag = -1;
        if(stu[i].dScore >= low && stu[i].cScore >=low){
            stu[i].flag = 4;
        }
        if(stu[i].dScore >= high && stu[i].cScore >= high){
            stu[i].flag = 1;
        }
        if(stu[i].dScore >= high && stu[i].cScore < high && stu[i].cScore>=low){
            stu[i].flag = 2;
        }
        if(stu[i].dScore>=low && stu[i].dScore<high && stu[i].dScore >= stu[i].cScore && stu[i].cScore>=low){
            stu[i].flag = 3;
        }
    }
    for(i=0;i<n;i++){
        if(stu[i].flag != -1){
            count++;
        }
    }
    int kk = 1;
    printf("%d\n",count);
    while(kk<=4){
        int j = 0;
        for(i=0;i<n;i++){
            if(stu[i].flag == kk){
                temp[j].cScore = stu[i].cScore;
                temp[j].dScore = stu[i].dScore;
                temp[j].num = stu[i].num;
                j++;
            }
        }
        if(temp != NULL){
            quickSort(temp,0,j-1);
            for(i=0;i<j;i++){
                printf("%d %d %d\n",temp[i].num,temp[i].dScore,temp[i].cScore);
            }
        }
        kk++;

    }

    return 0;
}

1017 A除以B (20 分)(大数除法)

本题要求计算 A/B,其中 A 是不超过 1000 位的正整数,B 是 1位正整数。你需要输出商数 Q 和余数 R,使得 A=B×Q+R 成立。

输入格式:
输入在一行中依次给出 A 和 B,中间以 1 空格分隔。

输出格式:
在一行中依次输出 Q 和 R,中间以 1 空格分隔。
原题链接
key:大数除法

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {

    char s[1000];
    int q;
    int i=0,j=0;
    int k,l=0;
    int kk=0;
    scanf("%s %d",s,&q);
    while(s[i] != '\0'){
        k = s[i] - '0';
        kk = kk*10+k;
        if(kk<q){
            if(i!=0){
                printf("0");
            }
            i++;
            continue;
        }else{
            l = kk / q;
            printf("%d",l);
            kk = kk % q;
        }
        i++;
    }
    //适用于一位数且 s<q
    if(i==1 && l == 0){
        printf("%d",l);
    }
    printf(" %d",kk);

    return 0;
}

740. 删除并获得点数

给你一个整数数组 nums ,你可以对它进行一些操作。

每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除 所有 等于 nums[i] - 1 和 nums[i] + 1 的元素。

开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。

示例 1:
输入:nums = [3,4,2]
输出:6
解释:
删除 4 获得 4 个点数,因此 3 也被删除。
之后,删除 2 获得 2 个点数。总共获得 6 个点数。

示例 2:
输入:nums = [2,2,3,3,3,4]
输出:9
解释:
删除 3 获得 3 个点数,接着要删除两个 2 和 4 。
之后,再次删除 3 获得 3 个点数,再次删除 3 获得 3 个点数。
总共获得 9 个点数。

原题链接
key:动态规划

  • 方法一:1、将数组排序,合并相同元素,在空位填充0,运用打家劫舍方法(动态规划)
class Solution {

    public int deleteAndEarn(int[] nums) {
        //排序
        int len = nums.length;
        for (int i = 0; i < len-1; i++) {
            int min = nums[i];
            int minI = i;
            for (int j = i; j < len; j++) {
                if(nums[j] < min){
                    min = nums[j];
                    minI = j;
                }
            }
            nums[minI] = nums[i];
            nums[i] = min;
        }
        //合并与填充
        int ans[] = new int[10000];
        int k = 0;
        ans[k] = nums[0];
        for (int i = 1; i < len ; i++) {
            if(nums[i] == nums[i-1]){
                ans[k] += nums[i];
            }else if(nums[i] != nums[i-1]+1){
                //填充0
                int l = nums[i-1],r = nums[i];
                for (int j = l+1; j < r; j++) {
                    k++;
                    ans[k] = 0;
                }
            }
            if(nums[i] != nums[i-1]){
                k++;
                ans[k] = nums[i];
            }
        }
        //动态规划,打家劫舍
        int ansLen = k+1;
       if(ansLen == 1){
           return ans[0];
       }
       if (ansLen == 2){
           return ans[0]>ans[1]? ans[0]:ans[1];
       }
       int a1 = 0,a2 = ans[0],a3 = ans[1];
       int temp = 0;
        for (int i = 2; i < ansLen; i++) {
            temp = (a1>a2? a1:a2) + ans[i];
            a1 = a2;
            a2 = a3;
            a3 = temp;
        }
        return a2>a3? a2:a3;
    }
}
  • 方法二:记录0-10000的个数,找到nums[]的最大值max,max+1即为动态规划的边界,ans[i]*i即为这个点的收益,最后运用动态规划
class Solution {
  
    public int deleteAndEarn(int[] nums) {

        int len = nums.length;
        int ans[] = new int[10001];
        int max = nums[0];
        for (int i = 0; i < len; i++) {
            if(max < nums[i]){
                max = nums[i];
            }
           ans[nums[i]]++;
        }
        //动态规划,打家劫舍
        int ansLen = max+1;
       if(ansLen == 1){
           return 0;
       }
       if (ansLen == 2){
           return ans[1];
       }
       int a1 = 0,a2 = 0,a3 = ans[1];
       int temp;
        for (int i = 2; i < ansLen; i++) {
            temp = (a1>a2? a1:a2) + ans[i]*i;
            a1 = a2;
            a2 = a3;
            a3 = temp;
        }
        return a2>a3? a2:a3;
    }
}

918. 环形子数组的最大和

给定一个由整数数组 A 表示的环形数组 C,求 C 的非空子数组的最大可能和。

在此处,环形数组意味着数组的末端将会与开头相连呈环状。(形式上,当0 <= i < A.length 时 C[i] = A[i],且当 i >= 0 时 C[i+A.length] = C[i])

此外,子数组最多只能包含固定缓冲区 A 中的每个元素一次。(形式上,对于子数组 C[i], C[i+1], …, C[j],不存在 i <= k1, k2 <= j 其中 k1 % A.length = k2 % A.length)

示例 1:
输入:[1,-2,3,-2]
输出:3
解释:从子数组 [3] 得到最大和 3

示例 2:
输入:[5,-3,5]
输出:10
解释:从子数组 [5,5] 得到最大和 5 + 5 = 10

示例 3:
输入:[3,-1,2,-1]
输出:4
解释:从子数组 [2,-1,3] 得到最大和 2 + (-1) + 3 = 4

示例 4:
输入:[3,-2,2,-3]
输出:3
解释:从子数组 [3] 和 [3,-2,2] 都可以得到最大和 3

示例 5:
输入:[-2,-3,-1]
输出:-1
解释:从子数组 [-1] 得到最大和 -1

原题链接
key:动态规划、环形问题

思路:
  • 不使用环的情况时,直接通过53题的思路,逐步求出整个数组中的最大子序和即可
  • 【重点】使用到了环,则必定包含 A[n-1]和 A[0]两个元素且说明从A1到A[n-2]这个子数组中必定包含负数【否则只通过一趟最大子序和就可以的=得出结果】,公式为sum-min(sum为数组和,min为最小序列和)
  • 同时需要考虑数组元素全为负数的情况,这时sum-min = 0,而max<0,应该取max作为环形数组的最大和,而不是0
    思路参考
class Solution {
    public static void main(String []args){
        Solution s = new Solution();
        int a[] = {1,-2,3,-2};
        System.out.println(s.maxSubarraySumCircular(a));
    }
    public int maxSubarraySumCircular(int[] nums) {
        int len = nums.length;
        if(len == 1){
            return nums[0];
        }
        //最大和和最小和
        int sumMax = nums[0],sumMin = nums[0];
        int max = sumMax,min = sumMin;
        //数组求和
        int sum=nums[0];

        for (int i = 1; i < len; i++) {
            sum += nums[i];
            if(sumMax > 0){
                sumMax += nums[i];
            }else{
                sumMax = nums[i];
            }
            if(sumMin < 0){
                sumMin += nums[i];
            }else{
                sumMin = nums[i];
            }
            if(sumMax > max){
                max = sumMax;
            }
            if(sumMin < min){
                min = sumMin;
            }
        }
        if(sum == min)
            return max;
        return max > sum-min? max:sum-min;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值