(题解)《算法零基础100讲》(第31讲) 多维枚举(一) - 入门

1、判断子序列(leetcode392

这题的思路是可以直接暴力进行模式匹配的,但是我们如果除了kmp算法以外,直接使用暴力的话是要进行回溯匹配处理。而这题是不用进行回溯,因为它不是连续的子串,而是子序列,只要找在t中找到s各个字符并且顺序一样就可以AC了。

class Solution {
    public boolean isSubsequence(String s, String t) {
       int i = 0 , j = 0;
        while(i < t.length() && j < s.length())
        {
            if(t.charAt( i ) == s.charAt(j)) j ++;
            i ++;
        }
        return j == s.length();
    }
}

2、搜索二维矩阵(leetcode240

这题的思路一开始是想用递归的,也就是说如果目标target大于当前的矩阵值,就递归搜索右和下,如果小于当前的矩阵值,就递归搜索左和右,并且设置了一个哨兵数组来观察是否已经遍历过。但是这样子会出错,后来看了题解之后就换了一种思路。、
这题比较好的做法有二分搜索和Z字型搜索:
二分搜索:将矩阵的每一行都进行对应的二分搜索,但是我发现有一个问题就是如果只进行单次条件的二分搜索会发生错误,比如下面这个二分搜索:

public   boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length ,n = matrix[0].length;
        for(int i = 0 ; i < m ; i ++)
        {
            int l = 0,r = n - 1 ;
            if(l == r)
            {
                if(matrix[i][l] == target)return true;
                else continue;
            }
            while(l < r)
            {
                int mid = (l + r) / 2;
                if(target == matrix[i][mid])return true;
                else if(target <= matrix[i][mid])r = mid;
                else l = mid + 1;
            }
        }
        return false;
    }

(这里的二分搜索对于数组中这种情况会出现只匹配了 -1 而没有匹配3这个数组元素,导致报错,所以应该进行两种情况的二分搜索。还有一个注意的点就是如果匹配的数组中只有一个元素,二分搜索的条件l < r是不会进行搜索的,所以要在前面加一个条件判断)

正确的写法:
    public   boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length ,n = matrix[0].length;
        for(int i = 0 ; i < m ; i ++)
        {
            int l = 0,r = n - 1 ;
            if(l == r)
            {
                if(matrix[i][l] == target)return true;
                else continue;
            }
            while(l < r)
            {
                int mid = (l + r) / 2;
                if(target == matrix[i][mid])return true;
                else if(target <= matrix[i][mid])r = mid;
                else l = mid + 1;
            }
            l = 0;
            r = n - 1 ;
            while(l < r)
            {
                int mid = (l + r + 1) / 2;
                if(target == matrix[i][mid])return true;
                else if(target >= matrix[i][mid])l = mid;
                else r = mid - 1;
            }
        }
        return false;
    }

Z字型搜索
我们可以从矩阵的右上角 (0, n-1)进行搜索。比如当前我们位于(x,y),那么搜索将要搜索的矩阵就是以(x,y)为右上角,原来矩阵的左下角为边界的一个子矩阵。
如果 matrix[x,y] == target,说明结果完成;
如果 matrix[x,y] < target,那么x所在的当前行的左边数都小于target,所以可以将x + 1,去下一行进行匹配。
如果matrix[x,y] > target,那么y所在的当前列以下的数都大于target,所以可以将y - 1,去前一列进行检测。

    public   boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length,n = matrix[0].length;
        int i = 0,j = n - 1;
        while( i < m && j >= 0 )
        {
            if(matrix[i][j] == target)return true;
            else if(matrix[i][j] > target)j--;
            else i ++;
        }
        return false;
    }

3、差的绝对值为 K 的数对数目(leetcode2006

这题相对来说还是比较容易的,两重for循环遍历数组进行判断。

       public   int countKDifference(int[] nums, int k) {
        int n = nums.length,amount = 0;
        for(int i = 0 ; i < n ; i++)
        {
            for(int j = i + 1; j < n ; j ++)
            {
                if(Math.abs(nums[i] - nums[j]) == k )amount ++;
            }
        }
        return amount;
    }

4、找不同(leetcode389

这题最开始的思路由于不算是模式匹配,只是要统计字符串中字符个数,找出t中和s不同的字符个数的字符就行了,所以是想到了HashMap进行解决。

    public static char findTheDifference(String s, String t) {
        Map<Character,Integer> map = new HashMap<>();
        Map<Character,Integer> map1 = new HashMap<>();
        //for循环存储s的字符以及个数
        for(int i = 0 ; i < s.length() ; i ++)
        {
            if(!map.containsKey(s.charAt(i)))
            {
                map.put(s.charAt(i),0);
            }
            else
            {
                int num = map.get(s.charAt(i));
                map.put(s.charAt(i),++num);
            }
        }
        //for循环存储t的字符以及个数
        for(int i = 0 ; i < t.length() ; i ++)
        {
            if(!map1.containsKey(t.charAt(i)))
            {
                map1.put(t.charAt(i),0);
            }
            else
            {
                int num = map1.get(t.charAt(i));
                map1.put(t.charAt(i),++num);
            }
        }
        //将s与t中存在的字符及其个数进行判断,返回差异的那一个字符
        for(Character c : map1.keySet())
        {
            if(!map1.containsKey(c))return c;
            else
            {
                if(map.get(c) != map1.get(c))return c;
            }
        }
        return 'a';
    }

其实还有更好的做法就是将s和t的字符串的ASCII码加起来,然后相减,因为是只添加了一个字符,所以相减的ASCII码转出来的字符就是添加的字符,比较灵活。

public char findTheDifference(String s, String t) {
        int amount= 0;
        for (int i = 0; i < s.length(); ++i) {
            amount^= s.charAt(i);
        }
        for (int i = 0; i < t.length(); ++i) {
            amount^= t.charAt(i);
        }
        return (char) amount;
    }

5、 拥有最多糖果的孩子(leetcode1431

相当于水题吧,首先建立一个boolean值的List数组,接着for循环找出数组中的最大值,然后再遍历,将数组的每个值加上额外的糖果数,如果大于该最大值,就将true加进去List数组中,否则将false加进去List数组中。

    public List<Boolean> kidsWithCandies(int[] candies, int extraCandies) {
        List<Boolean> li = new ArrayList<>();
        int max = candies[0];
        for(int i = 0 ; i < candies.length ; i++)
        {
            if(candies[i] > max)max = candies[i];
        }
        for(int i = 0 ; i < candies.length ; i++)
        {
            if((candies[i] + extraCandies) >= max)li.add(true);
            else li.add(false);
        }
        return li;
    }

6、所有奇数长度子数组的和(leetcode1588

可以利用前缀和的思想,然后每次遍历都是按奇数的次数来进行遍历条件的改变。

    public int sumOddLengthSubarrays(int[] arr) {
        int []a = new int[arr.length + 1];
        a[0] = 0;
        int amount = 0;
        for(int i = 1 ; i < a.length ; i ++)
        {
            a[i] = a[i - 1] + arr[i - 1];
        }
        for(int i = 1 ; i <= arr.length ; i +=2)
        {
            for(int j = i ; j <= arr.length ; j ++)
            {
                amount += a[j] - a[j - i];
                
            }
        }
        return amount;
    }

7、统计好三元组(leetcode1534

三重for循环进行遍历

    public int countGoodTriplets(int[] arr, int a, int b, int c) {
        int amount = 0;
        int n = arr.length;
        for(int i = 0 ; i < n - 2 ; i ++ )
        {
            for(int j = i + 1; j < n - 1 ; j ++)
            {
                for(int k = j + 1; k < n ; k ++)
                {
                    if(Math.abs(arr[i] - arr[j]) <=a && Math.abs(arr[j] - arr[k]) <=b && Math.abs(arr[i] - arr[k]) <=c)amount ++;
                }
            }
        }
        return amount;
    }

8、宝石与石头(leetcode771

利用HashSet存储宝石串,然后进行遍历统计。

    public int numJewelsInStones(String jewels, String stones) {
        int amount = 0;
        Set<Character> set = new HashSet<>();
        for(int i = 0 ; i < jewels.length() ; i ++)
        {
            set.add(jewels.charAt(i));
        }
        for(int i = 0 ; i < stones.length() ; i ++)
        {
            char c = stones.charAt(i);
            if(set.contains(c))amount++;
        }
        return amount;
    }

9、按既定顺序创建目标数组(leetcode1389

水题,一重循环进行遍历。

    public int[] createTargetArray(int[] nums, int[] index) {
        List<Integer> li = new ArrayList<>();
        for(int i = 0 ; i < nums.length ; i ++)
        {
            li.add(index[i],nums[i]);
        }
        int []num = new int[li.size()];
        for(int i = 0 ; i< num.length ; i ++)num[i] = li.get(i);
        return num;
    }

10、最长公共前缀(leetcode14

这题之前用C++写过,暴力遍历统计,可以以其中一个字符串作为模式串进行匹配,然后以匹配到最小的前缀为结果。

#include<string>
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
	
        if(strs.size()==1)return strs[0];
        int max_len=0,j;
        for(int i=1;i<strs.size();i++)
            {
            for(j=0;j<strs[i].size();j++)
                {
                if(strs[0][j]!=strs[i][j])break;
            }
            	if(i==1&&j!=0)max_len=j;
                else max_len=min(max_len,j);
        }
        string str;
        for(int i=0;i<max_len;i++)
            str+=strs[0][i];
        return str; 
    }
};

11、统计平方和三元组的数目

和前面的题有点相似,只不过for循环的条件改变为n而已,然后一般只需要交换a和b的值,但是交换a和b的值结果是一样的,c的值是一定会大于a和b的值,所以一次遍历下来,只要符合的结果就直接+2

    public int countTriples(int n) {
                int amount = 0;
        for(int i = 1 ; i <= n - 2 ; i ++ )
        {
            for(int j = i + 1; j <= n - 1 ; j ++)
            {
                for(int k = j + 1; k <= n ; k ++)
                {
                    if( (i*i + j * j) == k * k)amount+=2;
                }
            }
        }
        return amount;
    }

第一次写博客,写得不好请各位大大见谅和提议。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值