算法笔记

1、在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

示例:

现有矩阵 matrix 如下:

[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。

给定 target = 20,返回 false。

限制:

0 <= n <= 1000

0 <= m <= 1000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

很明显数组有一定的规律,即每行从左到右递增,每列从上往下递增,可以从右上开始进行判断,若给定值相等,return true,如果小于右上,则列–,否则行++,重复进行,直至得到相等的值,如果循环结束后仍不存在相同的值,则可以判定不存在,返回false

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return false;
        }
        int rows = matrix.length, columns = matrix[0].length;
        int row = 0, column = columns - 1;
        while (row < rows && column >= 0) {
            int num = matrix[row][column];
            if (num == target) {
                return true;
            } else if (num > target) {
                column--;
            } else {
                row++;
            }
        }
        return false;
    }
}
2、给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 1:

输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:

输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:

输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
示例 4:

输入: s = “”
输出: 0

提示:

0 <= s.length <= 5 * 104
s 由英文字母、数字、符号和空格组成

题解

​ 对于此题,我们要寻找的是一段连续字符串的最大不重复子串,因此可以采用双指针的方式进行查找,即窗口。左指针从字符串首字符开始查找,右指针设置为-1,即认为是指针末尾。另外设置一个HashSet集合用来存储不重复的字符,首先左指针不动,然后右指针不断右移,如果当前右指针所指示的字符不存在set中,则将该字符存入set集合中,同时右指针后移,重复进行,如果当前右指针已经存在set中,则从set集合中删除此字符,同时左指针右移。此时字符串长度为res-i+1

代码如下:

public int lengthOfLongestSubstring(String s) {
        int n = s.length();
        int res = -1, max=0;//设置右指针为-1,max用于存储最长字符长度,即最终结果
        Set<Character> set = new HashSet<Character>();//设置set集合存储字符判断字符是否出现过
        for(int i=0;i<n;++i){
            if(i!=0){
                //左指针右移,删除一个元素
                set.remove(s.charAt(i-1));
            }
            while(res+1<n && !set.contains(s.charAt(res+1))){
                //不断移动右指针
                set.add(s.charAt(res+1));
                res++;
            }
            //第i到res个字符是一个最长的字符串
            max = Math.max(max,res-i+1);
        }
        return max;
    }
3.请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

示例 1:

输入:s = “We are happy.”
输出:“We%20are%20happy.”

限制:

0 <= s 的长度 <= 10000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ti-huan-kong-ge-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

一、利用char数组存储新字符串

	public String replaceSpace(String s) {
        char[] chars = new char[s.length()*3];
        int size = 0;
        for(int i=0;i<s.length();i++){
            char c = s.charAt(i);
            if(c==' '){
                chars[size++]='%';
                chars[size++]='2';
                chars[size++]='0';
            }
            else{
                chars[size++]=c;
            }
        }
        String newStr = new String(chars, 0, size);
        return newStr;
    }

二、利用StringBuilder存储新字符串,利用append添加字符

 	public String replaceSpace(String s) {
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<s.length();i++){
            char c = s.charAt(i);
            if(c==' '){
                sb.append("%20");
            }else{
                sb.append(c);
            }
        }
        return sb.toString();
    }
4.给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:

输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:

输入:nums1 = [2], nums2 = []
输出:2.00000

提示:

nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106

进阶:你能设计一个时间复杂度为 O(log (m+n)) 的算法解决此问题吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

利用两个数组的指针进行数组的删除(理论上排除一部分不需要的值,同时需要修改k的值)

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int length1 = nums1.length, length2 = nums2.length;
        int totalLength = length1 + length2;
        if (totalLength % 2 == 1) {
            int midIndex = totalLength / 2;
            double median = getKthElement(nums1, nums2, midIndex + 1);
            return median;
        } else {
            int midIndex1 = totalLength / 2 - 1, midIndex2 = totalLength / 2;
            double median = (getKthElement(nums1, nums2, midIndex1 + 1) + getKthElement(nums1, nums2, midIndex2 + 1)) / 2.0;
            return median;
        }
    }public int getKthElement(int[] nums1, int[] nums2, int k) {/* 主要思路:要找到第 k (k>1) 小的元素,那么就取 pivot1 = nums1[k/2-1] 和 pivot2 = nums2[k/2-1] 进行比较

   * 这里的 "/" 表示整除
     s1 中小于等于 pivot1 的元素有 nums1[0 .. k/2-2] 共计 k/2-1 个
        * nums2 中小于等于 pivot2 的元素有 nums2[0 .. k/2-2] 共计 k/2-1 个
          ivot = min(pivot1, pivot2),两个数组中小于等于 pivot 的元素共计不会超过 (k/2-1) + (k/2-1) <= k-2 个
             * 这样 pivot 本身最大也只能是第 k-1 小的元素
               pivot = pivot1,那么 nums1[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums1 数组
                  * 如果 pivot = pivot2,那么 nums2[0 .. k/2-1] 都不可能是第 k 小的元素。把这些元素全部 "删除",剩下的作为新的 nums2 数组
                    们 "删除" 了一些元素(这些元素都比第 k 小的元素要小),因此需要修改 k 的值,减去删除的数的个数
                             */int length1 = nums1.length, length2 = nums2.length;int index1 = 0, index2 = 0;int kthElement = 0;while (true) {// 边界情况if (index1 == length1) {return nums2[index2 + k - 1];}if (index2 == length2) {return nums1[index1 + k - 1];}if (k == 1) {return Math.min(nums1[index1], nums2[index2]);}
​            
​            // 正常情况int half = k / 2;int newIndex1 = Math.min(index1 + half, length1) - 1;int newIndex2 = Math.min(index2 + half, length2) - 1;int pivot1 = nums1[newIndex1], pivot2 = nums2[newIndex2];if (pivot1 <= pivot2) {
​                k -= (newIndex1 - index1 + 1);
​                index1 = newIndex1 + 1;} else {
​                k -= (newIndex2 - index2 + 1);
​                index2 = newIndex2 + 1;}}}
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Aq1z4Rca-1619352644070)(C:\Users\Lin\AppData\Roaming\Typora\typora-user-images\image-20210425163606566.png)]

题解

一、使用递归,分别构建左子树和右子树。首先找到根节点在中序遍历中的位置,从而得到左子树和右子树的长度,进而递归构建(每次修改指针,指向下一个根节点(子树的根节点))

public class Solution1 {
    private Map<Integer,Integer> indexMap;
    public TreeNode myBuildTree(int[] preorder, int preorderLeft,int preorderRight, int[] inorder , int inorderLeft, int inorderRight) {
        if (preorderLeft>preorderRight){
            return null;
        }
        //查得头结点
        int pre_root = preorderLeft;
        int in_root = indexMap.get(preorder[pre_root]);
        //构建根节点
        TreeNode root = new TreeNode(preorder[pre_root]);
        //构建左子树
        int size_leftTree = in_root - inorderLeft;
        root.left = myBuildTree(preorder,preorderLeft+1,preorderLeft+size_leftTree,inorder,inorderLeft,in_root);
        //构建右子树
        root.right = myBuildTree(preorder,preorderLeft+size_leftTree+1,preorderRight,inorder,in_root+1,inorderRight);
        return root;
    }
    public TreeNode buildTree(int[] preorder,int[] inorder){
        int n = preorder.length;
        indexMap = new HashMap<>();
        for (int i = 0; i < n; i++) {
            indexMap.put(inorder[i],i);
        }
        return myBuildTree(preorder,0,n-1,inorder,0,n-1);
    }
}

解法二、使用迭代进行构建,利用栈进行构建,思路:将前序遍历的值进行压栈,直到找到左子树的根节点(此时栈顶的值等于中序遍历序列的第一个),然后转而构建右子树,同理进行迭代,对于中序遍历,需要一个指针,每次出栈指针后移一位。

public class Solution2 {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        int n = preorder.length;
        if (n<=0){
            return null;
        }
        //对中序遍历序列设置指针,从零开始指向第一个元素
        int index = 0;
        Deque<TreeNode> stack = new LinkedList<>();
        //构建根节点,并入栈
        TreeNode root = new TreeNode(preorder[0]);
        stack.push(root);
        //构建子树
        for (int i = 1; i < n; i++) {
            //取出栈顶元素
            TreeNode treeNode = stack.peek();
            //如果栈顶元素值不等于中序遍历指针对应的值,说明此元素为栈顶节点的左子树
            if (treeNode.val!=inorder[index]){
                //链接并入栈
                treeNode.left = new TreeNode(preorder[i]);
                stack.push(treeNode.left);
            }else {//此时说明已经找到左子树的最后一个元素,即最左下,依次弹出栈顶元素并将index指针后移一位,当栈顶元素值不等于指针对应元素的值时,说明当前i指针指向的值为前节点的右子树
                while (!stack.isEmpty()&&stack.peek().val==inorder[index]){//此处treeNode=刚才弹出的栈顶元素,不能使用,仍需使用peek()取出此时的栈顶元素的值
                    treeNode = stack.pop();
                    ++index;
                }
                //连接右子树,并压栈
                treeNode.right = new TreeNode(preorder[i]);//前序遍历总是根节点优先访问
                stack.push(treeNode.right);
            }
        }
        return root;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值