leetcode(3) 10.4-10.9

3. 无重复字符的最长字串

给定一个字符串 s ,请你找出其中不含有重复字符最长子串 的长度。

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

方法:滑动窗口
  • 我们使用两个指针表示字符串中的某个子串(或窗口)的左右边界。
  • 在每一步的操作中,我们会将左指针向右移动一格,表示 我们开始枚举下一个字符作为起始位置,然后我们可以不断地向右移动右指针,但需要保证这两个指针对应的子串中没有重复的字符。
  • 在移动结束后,这个子串就对应着 以左指针开始的,不包含重复字符的最长子串。我们记录下这个子串的长度;
  • 在枚举结束后,我们找到的最长的子串的长度即为答案。
class Solution {
    public int lengthOfLongestSubstring(String s) {
        HashMap<Character,Integer> map = new HashMap<Character,Integer>();
        if( s.length() == 0 ) return 0; 
        int l = 0 , r = 0 ;
        for(int i=0 ; i<s.length() ; i++){
            if( map.containsKey( s.charAt(i) )){
                l = Math.max( l , map.get( s.charAt(i) ) + 1 ) ;
            }
            map.put(s.charAt(i),i);
            r = Math.max( r , i - l + 1 );
        }
        return r ;
        }
    }

567. 字符串的排列

给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。
如果是,返回 true ;否则,返回 false 。
换句话说,s1 的排列之一是 s2 的 子串

示例1:
输入:s1 = “ab” s2 = “eidbaooo”
输出:true
解释:s2 包含 s1 的排列之一 (“ba”).
示例 2:
输入:s1= “ab” s2 = “eidboaoo”
输出:false

方法: 滑动窗口

567讲解视频

class Solution {
    public boolean checkInclusion(String s1, String s2) {
        int L1 = s1.length();
        int L2 = s2.length();
        if( L1 > L2 ) return false;//L1一定比L2要小
        HashMap<Character,Integer> map1 = new HashMap<Character,Integer>();
        HashMap<Character,Integer> map2 = new HashMap<Character,Integer>();

        //将字符串s1 加入hashmap中 使用map1记录s1中的字符及其对应的个数
        for(char ch : s1.toCharArray() )
            map1.put( ch , map1.getOrDefault( ch , 0) + 1 );

        int index = 0;
        for( int i = 0 ; i<L1 ; i++){
            char a = s2.charAt(i);
            map2.put( a , map2.getOrDefault( a , 0 ) + 1 );
            index++;
        }

        while( index < L2){
            if( map2.equals(map1)) return true ;
            char l = s2.charAt( index - L1 );
            char r = s2.charAt( index );
            
            //左边界移动 移除操作
            map2.put( l , map2.get(l) - 1 );
            if( map2.get(l) == 0 )  map2.remove( l ) ;

            //右边界移动  加入操作
            map2.put( r , map2.getOrDefault( r , 0 ) + 1 );
            index++;
        }
        return map2.equals(map1);
    }
}

>岛屿问题

200. 岛屿数量
463.岛屿周长
695. 岛屿的最大面积
827. 最大人工岛

岛屿问题类通用解法、dfs遍历框架

733. 图像渲染

有一幅以二维整数数组表示的图画,每一个整数表示该图画的像素值大小,数值在 0 到 65535 之间。
给你一个坐标 (sr, sc) 表示图像渲染开始的像素值(行 ,列)和一个新的颜色值 newColor,让你重新上色这幅图像。
为了完成上色工作,从初始坐标开始,记录初始坐标的上下左右四个方向上像素值与初始坐标相同的相连像素点,接着再记录这四个方向上符合条件的像素点与他们对应四个方向上像素值与初始坐标相同的相连像素点,……,重复该过程。将所有有记录的像素点的颜色值改为新的颜色值。
最后返回经过上色渲染后的图像 。

示例 1:
输入:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
输出: [[2,2,2],[2,2,0],[2,0,1]]
解析:
在图像的正中间,(坐标(sr,sc)=(1,1)),
在路径上所有符合条件的像素点的颜色都被更改成2。
注意,右下角的像素没有更改为2,
因为它不是在上下左右四个方向上与初始点相连的像素点。

class Solution {
    public int[][] floodFill(int[][] image, int sr, int sc, int newColor) {
        int curColor = image[sr][sc]; //记录初始颜色
        //如果当前颜色与新色不同 则进行染色
        if( curColor != newColor ) {
            dfs( image , sr , sc , curColor , newColor );
        }
        return image;
    }

    public void dfs(int[][] image, int x, int y, int curColor , int newColor){
        // 剔除特殊条件 长宽越界、像素不等于初始值时不需要改色
        if( x<0 || x>=image.length || y<0 || y>=image[0].length || image[x][y] != curColor)  return ; 
        //改色 四个方向递归
        image[x][y] = newColor ;
        dfs(image , x-1 , y , curColor , newColor);
        dfs(image , x+1 , y , curColor , newColor);
        dfs(image , x , y-1 , curColor , newColor);
        dfs(image , x , y+1 , curColor , newColor);
    }
}

200. 岛屿数量

给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。

示例 1:
输入:grid = [
[“1”,“1”,“1”,“1”,“0”],
[“1”,“1”,“0”,“1”,“0”],
[“1”,“1”,“0”,“0”,“0”],
[“0”,“0”,“0”,“0”,“0”]
]
输出:1

class Solution {

    public int numIslands(char[][] grid) {
        //判断网格是否为空,如果为空则直接返回
        if( grid==null || grid.length==0 ) return 0;

        int count = 0 ; //记录岛屿数量
        for( int i = 0 ; i < grid.length ; i++ ){
            for(int j = 0 ; j < grid[0].length ; j++ ){
                if(grid[i][j] == '1' ){ //当存在1时表示当前存在一个岛屿
                    ++count;
                    dfs(grid,i,j);
                }
            }
        }
        return count;
    }

    public void dfs (char[][] grid , int x ,int y){ 
        //用于判断dfs中的下标是否出界 若出界 则直接返回
        if( x<0 || y<0 || x>=grid.length || y>=grid[0].length || grid[x][y] == '0') 
            return ; 
        //遍历过的地方标记为0  下次可直接跳过
        grid[x][y] = '0';
        dfs(grid,x-1,y);
        dfs(grid,x+1,y);
        dfs(grid,x,y-1);
        dfs(grid,x,y+1);
    }
}

695.岛屿的最大面积

给你一个大小为 m x n 的二进制矩阵 grid 。
岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。
岛屿的面积是岛上值为 1 的单元格的数目。
计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。
岛屿面积

class Solution {
    public int maxAreaOfIsland(int[][] grid) {
        //判断岛屿是否为空
        if( grid==null || grid.length==0 ) return 0 ;

        //记录岛屿面积
        int area=0;
        for(int i= 0 ; i<grid.length ; i++ ){
            for(int j=0 ; j<grid[0].length ; j++ ){
                if(grid[i][j]== 1 ){//如果为1 则开始搜索
                    int a = dfs(grid,i,j);//每当搜索到1时 dfs
                    area = Math.max(a,area);//保留岛屿面积较大的数据
                }
            }
        }
        return area;
    }
    public int dfs(int[][] grid,int x , int y){
        //判断特殊情况  
        if( x<0 || y<0 || x>=grid.length || y>=grid[0].length || grid[x][y] != 1)
            return 0;
        grid[x][y] = 2 ; //将遍历过的岛屿 置为其他值
        int num = 1; 
        return 1 + dfs(grid,x+1,y) + dfs(grid,x-1,y) + dfs(grid,x,y+1) + dfs(grid,x,y-1); 
    }
}

617.合并二叉树

给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
合并二叉树

方法:dfs
  • 可以使用深度优先搜索合并两个二叉树。从根节点开始同时遍历两个二叉树,并将对应的节点进行合并。两个二叉树的对应节点可能存在以下三种情况,对于每种情况使用不同的合并方式。
    • 如果两个二叉树的对应节点都为空,则合并后的二叉树的对应节点也为空;
    • 如果两个二叉树的对应节点只有一个为空,则合并后的二叉树的对应节点为其中的非空节点;
    • 如果两个二叉树的对应节点都不为空,则合并后的二叉树的对应节点的值为两个二叉树的对应节点的值之和,此时需要显性合并两个节点。
  • 对一个节点进行合并之后,还要对该节点的左右子树分别进行合并。这是一个递归的过程。
class Solution {
    // 主函数可自己递归
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
        if( root1 == null ) return root2;
        if( root2 == null ) return root1;
        //二叉树的前序遍历 
        root1.val += root2.val;  //中
        root1.left = mergeTrees(root1.left,root2.left);//左
        root1.right = mergeTrees(root1.right, root2.right);//右
        return root1; 
    }
}

剑指offer 05. 替换空格

请实现一个函数,把字符串 s 中的每个空格替换成"%20"。

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

方法:遍历增加。在Java语言中,字符串被设计成【不可变】类型,即无法直接修改字符串某一位字符,需要新建一个字符串实现。
class Solution {
    public String replaceSpace(String s) {
        // 遍历添加 - java语言特性:字符串类型被设计为 【不可变】类型
        // 即 无法直接修改字符串的某一位字符
        StringBuilder sc = new StringBuilder();
        for(Character c:s.toCharArray()){
            if( c == ' ') sc.append("%20");
            else sc.append(c);
        }
        return sc.toString();
    }
}
  • 时间复杂度:O(N),遍历使用O(N),每轮修改字符操作使用O(1).
  • 空间复杂度:O(N),新建都使用了线性大小的额外空间。

剑指offer 58-II. 左旋转字符串

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
示例 2:
输入: s = “lrloseumgh”, k = 6
输出: “umghlrlose”

方法: 字符串翻转、双指针 (参考反转字符串II的思想,将字符串分段分别反转,三次反转)
class Solution {
    public String reverseLeftWords(String s, int n) {
        char[] sc = s.toCharArray();
        int l=0 , r=n-1 ;
        reverse(sc,l,r);
        l = n ; r = s.length() -1 ;
        reverse(sc,l,r);
        l = 0 ; r = s.length() -1 ;
        reverse(sc,l,r);
        return String.valueOf(sc);
    }
    void reverse (char[] a ,int l ,int r){
        while(l<r){
            char b;
            b = a[l];
            a[l]=a[r];
            a[r]=b;
            l++;
            r--;
        }
    }
}
  • 时间复杂度:O(N)
  • 空间复杂度:O(N)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值