LeetCode 1351, 1, 208
1351. 统计有序矩阵中的负数标题链接
1351. 统计有序矩阵中的负数
标签
数组 二分查找 矩阵
简答二分查找
思路
由于矩阵每行都是按 降序 排列的,以是可以针对每行都使用二分查找来查找最后一个不是负数的元素的索引,然后给 总数 加上 本行元素个数 减去 这个索引 再 减一,不外要注意的一点是,最后一个不是负数的元素大概是重复的,以是不能在找到最后一个不是负数的元素后就退出查找,而应该继续到 右子区间 查找,直到找到 最右边的 不是最后一个负数的元素。
代码
class Solution {
public int countNegatives(int[][] grid) {
int m = grid.length; // m是矩阵的列数
int left, right;
int cnt = 0; // 统计负数的个数
for (int[] row : grid) { // 针对矩阵的每行进行操作
// 每次都把查找区间限制在 之间
left = 0;
right = m - 1;
while (left <= right) {
int mid = left + (right - left >> 1);
if (0 > row) { // 如果 row < 0
right = mid - 1; // 则到左子区间查询(降序数组)
} else if (0 < row) { // 如果 row > 0
left = mid + 1; // 则到右子区间查询(降序数组)
} else { // 如果 row == 0
left = mid + 1; // 则到右子区间查询(降序数组)
}
}
cnt += m - right - 1; // 统计本行的负数个数
}
return cnt;
}
}
优化
思路
像上面的多个二分查找之间没有任何接洽,每次都是在 [ 0 , m − 1 ] 这个大区间举行查询,如许就浪费了这个矩阵的另一个特性:每列也是按降序排列的。
那么该怎样使用这个特性呢?很简朴,有这个特性再加上每行都是降序排列的,就意味着 在上一行中最后一个0出现的位置 一定比 本行中最后一个0出现的位置 要更靠右或相同,以是二分查找本行时不需要将右端点重置为 m - 1,继承上一次的右端点即可。
代码
class Solution {
public int countNegatives(int[][] grid) {
int m = grid.length;
int left, right = m - 1;
int cnt = 0;
for (int[] row : grid) {
left = 0;
while (left <= right) {
int mid = left + (right - left >> 1);
if (0 > row) {
right = mid - 1;
} else if (0 < row) {
left = mid + 1;
} else {
left = mid + 1;
}
}
cnt += m - right - 1;
}
return cnt;
}
}
1. 两数之和
标题链接
1. 两数之和
标签
数组 哈希表
思路
本题需要返回元素对应的索引,而不是只返回真假值,以是可以使用 Map 来存储元素的值和索引的键值对,key为元素的值,value为元素的索引。每遍历到一个元素就在 Map 中查找是否有 目标元素 减去 当前元素 的元素,如果有,则返回当前元素和这个元素的索引构成的数组;否则就把当前元素的值和索引存储到 Map 中,遍历下一个元素。
代码
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int curr = nums; // 当前遍历到的元素
int need = target - curr; // 需要的元素,满足 当前元素 + 需要元素 = 目标元素
if (map.containsKey(need)) {
return new int[]{i, map.get(need)};
}
map.put(curr, i);
}
return null;
}
}
208. 实现 Trie (前缀树)
标题链接
208. 实现 Trie (前缀树)
标签
设计 字典树 哈希表 字符串
思路
本题和 二叉树 有些类似,不外本题是以 小写字符 作为区分子节点的标识,故应该叫 二十六叉树,每个节点都有26个指针,分别指向从 'a' 到 'z' 的所有字符的节点。
可以把字符串想像成一串字符序列,而这个字符序列就是二十六叉树的 一条路径,好比对于字符串word = "apple",它的路径就是a -> p -> p -> l -> e,按照路径把这个字符串添加到各层节点上。这就是添加方法 void insert(String word)。
在查找时,可以查找这个字符串的字符序列对应的路径是否存在与这个二十六叉树中,即按照这个路径遍历,如果有一个节点不存在,则这个字符串不存在;否则就代表字符串一定存在吗?不一定,例如只添加了一个字符串"apple",而现在要查询"app"是否存在。
那么就不能只保存路径,应该还要保存字符串的结尾字符,也就是保存这个字符是否是字符串的结尾,如许在查找时,就可以通过是否是字符串的结尾来判断这个单词是否存在了。这就是查询方法boolean search(String word)。
此外,还要实现boolean startsWith(String prefix)方法。这个方法就是 没添加是否是字符串的结尾的标志前 的查找方法,只要存在这条路径就满意条件,返回true;否则就返回false。
代码
class Trie {
private static class Node {
private static final int SIZE = 26; // 字符数
Node[] nexts = new Node; // 存储下一字母的指针数组
boolean isEnd; // 记录本节点是否是单词的结尾
}
private Node root; // 前缀树的根节点
public Trie() {
root = new Node();
}
public void insert(String word) {
char[] str = word.toCharArray();
Node curr = root;
for (char c : str){
int idx = c - 'a'; // 获取在指针数组中的索引
if (curr.nexts == null) { // 如果这个位置没有字符节点
curr.nexts = new Node(); // 则新建一个字符节点
}
curr = curr.nexts; // 往下一个字符节点移动
}
curr.isEnd = true; // 保存该字符是字符串的最后一个字符
}
public boolean search(String word) {
char[] str = word.toCharArray();
Node curr = root;
for (char c : str) {
int idx = c - 'a'; // 获取在指针数组中的索引
if (curr.nexts == null) { // 如果这个位置没有字符节点
return false; // 则说明字符串不存在该树中,返回false
}
curr = curr.nexts; // 往下一个字符节点移动
}
return curr.isEnd; // 返回这个字符是否是字符串的结尾
}
public boolean startsWith(String prefix) {
char[] str = prefix.toCharArray();
Node curr = root;
for (char c : str) {
int idx = c - 'a'; // 获取在指针数组中的索引
if (curr.nexts == null) { // 如果这个位置没有字符节点
return false; // 则说明该树中的字符串不以 prefix 为前缀,返回false
}
curr = curr.nexts; // 往下一个字符节点移动
}
return true; // 该树中一定有字符串以prefix为前缀,返回true
}
}
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]