了解项目常见问题积累中,减少bug。
校验数据,再使用数据
// url获取文件后缀名(图片) 【2021.3.12】 String split过滤异常!
String suffix = str.substring(str.lastIndexOf(".") + 1
了解便于快速运用到项目中。
Map<Long, MtPointAlarmStaticsDay> dayMap = dayList.stream().
collect(Collectors.toMap(MtPointAlarmStaticsDay::getPointConfId,
Function.identity(), (k1, k2) -> k2));
//k1,k2 表示value 值
// 常规分组
Map<City, Set<String>> namesByCity=people.stream().collect(
groupingBy(Person::getCity, mapping(Person::getLastName, toSet())));
list.stream().collect(Collectors.groupingBy(e->e.getProperty()));
Map<Long, MtPointAlarmStaticsHour> hourMap = hourList.stream().filter(Objects::nonNull)
.filter(e -> e.getStatisticDate().compareTo(minNow) == 0)
.collect(Collectors.toMap(k -> k.getPointConfId(),
v -> new MtPointAlarmStaticsHour().setPointConfId(v.getPointConfId())
.setStatisticDate(v.getStatisticDate())
.setAlarmNum(v.getAlarmNum())
.setDeviceNum(v.getDeviceNum())
.setGatewayNum(v.getGatewayNum()), (x, y) -> {
x.setAlarmNum(x.getAlarmNum() + y.getAlarmNum());
x.setGatewayNum(x.getGatewayNum() + y.getGatewayNum());
x.setDeviceNum(x.getDeviceNum() + y.getDeviceNum());
return x;
}));
Map<Long,Integer>
browseMap = browseList.stream().
collect(Collectors.groupingBy(SkAccidentBrowseRecord::getAccidentId, Collectors.summingInt(SkAccidentBrowseRecord::getBrowseNum)));
Map<String, Long> monitorTypeMap = pointConfList.stream()
.collect(Collectors.groupingBy(p -> p.getMonitorType(), Collectors.counting()));
//多个字段,分组求和(先按datas分组,再按Carrierid分组,求和)
Map<String, Map<String, LongSummaryStatistics>> enusersCollect2 =
li.stream().collect(Collectors.groupingBy(DataStatisticsResultMiddle::getDatas,
Collectors.groupingBy(DataStatisticsResultMiddle::getCarrierid,
Collectors.summarizingLong(DataStatisticsResultMiddle::getEnusers))));
// 聚合各个指标年标准值
Map<Long, BigDecimal> monitorIndexMap = relList.stream().collect(Collectors.groupingBy(HjDischargeMonitorItemRet::getMonitorItemId,
Collectors.collectingAndThen(Collectors.toList(), m -> {
return m.stream().map(v -> v.getYearStandardQuantity())
.reduce(BigDecimal.ZERO, BigDecimal::add);
})));
// 1. 集合方式
userList.sort((o1, o2) -> o1.getName().compareTo(o2.getName()));
// 2. Comparator
userList.sort(Comparator.comparing(UserVO::getAge));
// 3. Stream方式 排完序后倒序
List<UserVO> ret = userList.stream()
.sorted(Comparator.comparing(UserVO::getAge).reversed())
.collect(Collectors.toList());
// 4. Stream方式 直接计算倒序
List<UserVO> ret2 = userList.stream()
.sorted(Comparator.comparing(UserVO::getAge,Comparator.reverseOrder()))
.collect(Collectors.toList());
// 1.集合方式
Collections.sort(userList, Comparator.comparing(UserVO::getName)
.thenComparingInt(UserVO::getAge));
// 2.Stream 方式
List<UserVO> ret = userList.stream()
.sorted(Comparator.comparing(UserVO::getName).thenComparingInt(UserVO::getAge))
.collect(Collectors.toList());
//1. 集合方式
Collections.sort(userList, Comparator.nullsFirst(Comparator.comparing(UserVO::getAge)).reversed());
// 2.Stream 方式
List<UserVO> ret = userList.stream() .sorted(Comparator.nullsFirst(Comparator.comparing(UserVO::getAge,Comparator.nullsLast(String::compareTo))))
.collect(Collectors.toList());
了解数据结构、算法思想、优缺点、合理运用到项目中, 常见算法:
模式串匹配的意义在于,如果我是一个平台的管理员,我可以针对一篇文章或者一句话,搜索其中某个特定脏字或者不雅词汇的出现次数、位置——次数可以帮助我决定采取何种等级对于该用户的惩罚方式,而位置则可以帮助我给每一个脏词打上“*”的标记来自动屏蔽这些脏词;
KMPKMP 的精髓在于,对于每次失配之后,我都不会从头重新开始枚举,而是根据我已经得知的数据,从某个特定的位置开始匹配;而对于模式串的每一位,都有唯一的“特定变化位置”,这个在失配之后的特定变化位置可以帮助我们利用已有的数据不用从头匹配,从而节约时间。
程序 = 数据结构 + 算法
了解数据结构、算法思想、优缺点、合理运用到项目中, 常见算法:
时间复杂度:
O(1) -> HashMap
O(logn)-> 二叉树、二分法
O(n) -> for 循环
O(nlogn) -> for循环嵌套二叉树 、 Arrays.sort、快排
O(n2) -> for循环嵌套
…
时间复杂度由小 到大为:
O(1) < O(log2n) < O(n) < O(n log2n) <O(n2)<O(n3) …<O(2n)<O(n!)
时间复杂度: 冒泡 < 选择 < 插入
/**
* (量级过10W时非常慢)
* 冒泡排序(相邻数据比较)
*
* @param nums
*/
public static void bubbleSort(int[] nums) {
int length = nums.length;
for (int i = 0; i < nums.length; i++) {
for (int j = 1; j < length; j++) {
if (nums[j - 1] > nums[j]) {
int temp = nums[j - 1];
nums[j - 1] = nums[j];
nums[j] = temp;
}
}
}
}
/**
* 插入数据排序 (一轮可能会换多个) 从左到右再到左排序,再遍历... 一直到截止。
* <p>
* 核心: 指定节点(用插入节点与节点以前的数据进行排序)
*
* @param nums 集合
*/
public static void insertSort(int[] nums) {
int insertNode;
int j;
for (int i = 1; i < nums.length; i++) {
insertNode = nums[i];
j = i - 1;
while (j >= 0 && insertNode < nums[j]) {
nums[j + 1] = nums[j];
j--;
}
nums[j + 1] = insertNode;
}
}
/**
* 选择排序 (一轮只换一个)
* <p>
* 核心: 确定当前节点,然后索引++节点后面排序,然后替换。
*
* @param nums 集合
*/
public static void selectSort(int[] nums) {
for (int i = 0; i < nums.length; i++) {
int pos = i;
for (int j = i + 1; j < nums.length; j++) {
if (nums[pos] > nums[j]) {
pos = j;
}
}
if (pos != i) {
int temp = nums[i];
nums[i] = nums[pos];
nums[pos] = temp;
}
}
}
程序 = 数据结构 + 算法
了解数据结构、算法思想、优缺点、合理运用到项目中, 常见算法:
时间复杂度:
O(1) -> HashMap
O(logn)-> 二叉树
O(n) -> for 循环
O(nlogn) -> for循环嵌套二叉树 、 Arrays.sort
O(n2) -> for循环嵌套
…
时间复杂度由小 到大为:
O(1) < O(log2n) < O(n) < O(n log2n) <O(n2)<O(n3) …<O(2n)<O(n!)
有序的数组,效率 O(logn)
实例: 猜数字 100 ,需要猜多少次 (log128)
对数与幂运算互为逆运算。(幂运算表示指数个底数相乘)
public class BinaryTest
{
public static int binary(int[] array, int value)
{
if(array == null || array.length ==0)
{
return -1;
}
int start = 0;
int end = array.length - 1;
int middle;
while(start+1 < end)
{
middle = start+(end - start) / 2;
if(value == array[middle])
{
return middle;
}
if(value > array[middle])
{
start = middle;
}
if(value < array[middle])
{
end = middle;
}
}
if(value==array[start])
{
return start;
}
if(value==array[end])
{
return end;
}
return -1;
}
public static void main(String[] args)
{
int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int value = binary(a, 9);
System.out.println(value);
}
}
//数学: 2、4象限 通用
public class BinaryTest
{
public static int binary(int[] array, int value)
{
if(array == null || array.length ==0)
{
return -1;
}
int start = 0;
int end = array.length - 1;
int middle;
while(start+1 < end)
{
//middle 随着start、end 变化而变化
middle = start+(end - start) / 2;
if(value == array[middle])
{
return middle;
}
//确定升序,还是降序
if(array[middle] > array[start])//升序
{
//在start 和 middle
if(value <= array[middle] && value>=array[start])
{
end = middle;
}else
{
start = middle;
}
}
else
{
if(value >=array[middle] && value <=array[end])
{
start = middle;
}
else
{
end =middle;
}
}
}
if(value==array[start])
{
return start;
}
if(value==array[end])
{
return end;
}
return -1;
}
public static void main(String[] args)
{
int[] a = { 7, 8, 9,1, 2, 3, 4, 5, 6};
int value = binary(a, 9);
System.out.println(value);
}
}
class Solution {
public int findMin(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
int start = 0;
int end = nums.length - 1;
int mid;
while (start + 1 < end ) {
mid = start + (end - start) / 2;
//正序
if (nums[mid] >= nums[start]) {
if (nums[end] <= nums[mid]) {
start = mid;
} else {
end = mid;
}
} else {
//end =mid; ??
start = mid;
}
}
return Math.min(nums[start], nums[end]);
}
}
class solution1{
public int findPeakElement(int[] nums)
{
if(nums == null || nums.length==0)
{
return -1;
}
int start = 0;
int end = nums.length -1;
int mid;
while(start+1 < end)
{
mid = start + (end-start)/2;
if(nums[mid]<nums[mid-1])
{
end= mid;
}
else if(nums[mid]<nums[mid+1])
{
start = mid;
}
else
{
return mid;
}
}
return nums[start]>nums[end] ? start:end;
}
}
public class CutWood {
public static void main(String[] args) {
int[] nums = {612, 301, 257, 900};
System.out.println(new CutWood().cutWood(nums, 10));
}
/**
* 将一堆木头切成指定的块数,求出单块木头最大长度
*
* @param nums 木头集合
* @param k 块数
* @return 单块木头最大长度
*/
public int cutWood(int[] nums, int k) {
if (nums == null || nums.length == 0) {
return 0;
}
int start = 1;
int end = getMax(nums);
int mid;
while (start + 1 < end) {
mid = start + (end - start) / 2;
int pieces = getPieces(nums, mid);
//能够切分,但不一定是单个最长的木头
if (pieces > k) {
start = mid;
} else {
end = mid;
}
}
if (getPieces(nums, start) >= k) {
return start;
}
if (getPieces(nums, end) >= k) {
return end;
}
return 0;
}
private int getPieces(int[] nums, int mid) {
int pieces = 0;
for (int num : nums) {
pieces += num / mid;
}
return pieces;
}
private int getMax(int[] nums) {
int max = 0;
for (int num : nums) {
if (num > max) {
max = num;
}
}
return max;
}
}
//输出结果为 153
分析:
1. 常规算法,双for循环嵌套,时间复杂度为:n<sup>2</sup>
2. 采用双指针将时间复杂度降为 n