Algorithm
字符串相加
思路:因为可能超过 Integer 最大值,所以用竖式相加 方式,用每一位进行计算,并保留进位。
将进位参与下一位的计算中
字符串长短不一,对于短的地方进行补 0 即可
class Solution {
public String addStrings(String num1, String num2) {
// 竖式计算,从末位开始 相加,如果大于10将 进行进位。 有可能不相等,
// 对于短的部分,再进行计算时候认为是0
int i= num1.length()-1; int j=num2.length()-1;
int addFlag=0;
StringBuilder str=new StringBuilder();
while(i>=0 || j>=0 ){
int x= i>=0? num1.charAt(i)-'0':0;
int y= j>=0? num2.charAt(j)-'0':0 ;
int thisSum = x+y+addFlag;
str.append(thisSum % 10); //
addFlag= thisSum/10;
i--;
j--;
}
// 最后两个字符串 都遍历完,最高位存在进位,则要记录下来
if(addFlag!=0){
str.append(addFlag);
}
str.reverse();
return str.toString();
}
}
复制代码
类似的算法题
字符串相乘
class Solution {
public String multiply(String num1, String num2) {
// 示例 1234 * 567 其中1234是被乘数,567是乘数
if(num1.equals("0")|| num2.equals("0")) return "0";
String result="";
// 从乘数num2最后一位开始 逐位往左 与 被乘数num1 得到的结果 进行相加
for(int i=num2.length()-1;i>=0;i--){
int x=num2.charAt(i)-'0';
int countBit=0;
StringBuilder thisLevelResult=new StringBuilder();
// 补0 最后一位不用补,倒数第二位要补一个0,倒数第三位要补2个0
for(int m=0; m<num2.length()-1-i; m++){
thisLevelResult.append("0");
}
// 计算 每一位 与被乘数的结果
for(int j=num1.length()-1; j>=0;j--){
int y= num1.charAt(j)-'0';
int thisResult= x*y+countBit;
thisLevelResult.append(thisResult%10);
countBit=thisResult/10;
}
if(countBit>0){
thisLevelResult.append(countBit);
}
result=addTwoNumStr(thisLevelResult.reverse().toString(),result.toString());
}
return result;
}
public String addTwoNumStr(String num1, String num2){
if(num1.length()==0|| num1=="0"){
return num2;
}
if(num2.length()==0|| num2=="0"){
return num1;
}
int i=num1.length()-1;
int j=num2.length()-1;
StringBuilder result=new StringBuilder();
int addBit=0;
while(i>=0||j>=0){
int x= i>=0? num1.charAt(i)-'0':0;
int y= j>=0? num2.charAt(j)-'0':0;
int thisResult=x+y+addBit;
result.append(thisResult%10);
addBit=thisResult/10;
i--;
j--;
}
if(addBit>0){
result.append(addBit);
}
return result.reverse().toString();
}
}
复制代码
Review
https://unixism.net/2019/04/linux-applications-performance-introduction/
文章对并发模型中 Linux 下网络 I/O 处理模型 进行性能测试
纵轴是并发连接数,横轴系统可以支持的最大 QPS(性能)
当并发连接数是 1000 的时候,可以看出 preforking、prethreaded、epoll 三种模式性能是相近的,也意味着 epoll 并不是在任何场景都具备相比其它模式的性能优势。
prethreaded 模式(作者源码中设置了 100 个线程)在 11000 并发的时候性能有 2200,但 12000 并发连接的时候,性能急剧下降到只有 970,推测是 12000 并发的时候触发了 C10K 问题,线程上下文切换的性能消耗超越了 IO 处理,成为了系统的处理瓶颈。
表格纵向比较时候,看数据变化较大的部分
创建进程的消耗是创建线程的消耗的 4 倍左右。
并发 2000 以内时,preforked、prethreaded、epoll 的性能相差无几,甚至 preforked 和 prethreaded 的性能有时候还稍微高一些。
这也是内部系统、中间件等并发数并不高的系统并不一定需要 epoll 的原因,用 preforked 和 prethreaded 模式能够达到相同的性能,并且实现要简单。
当并发数达到 8000 以上,只有 pthreaded 和 epoll 模式能够继续运行,但性能也有下降,epoll 的下降更加平稳一些。
prethreaded 模式在 12000 并发连接的时候,性能急剧下降
poll 模式随着并发数增多稳定下降,因为需要遍历的描述符越多,其性能越低。
epoll 在并发数超过 10000 的时候性能开始下降,但下降比较平稳。不管并发连接数是多少个,从 epoll 的数据看,都是 2000+一点,也就是这个系统的 QPS 只能达到 2000+。
这个结论看起来比较简单,但是却隐含着一个关键的设计点:epoll 不是万能的,连接数太多的时候单进程 epoll 也是不行的。这也是为什么 Redis 可以用单进程 Reactor 模式,而 Nginx 必须用多进程 Reactor 模式,因为 Redis 的应用场景是内部访问,并发数一般不会超过 10000;而 Nginx 是互联网访问,并发数很容易超过 10000。
结合极客时间专栏看了一下
Tips
主题:excel 读写
POI 方式
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>4.1.2</version>
</dependency>
复制代码
List<Performance> processData = Lists.newArrayList();
InputStream dataInputStream = TestController.class.getResourceAsStream("/处理数据.xlsx");
// 读取整个Excel
XSSFWorkbook sheets = null;
try {
sheets = new XSSFWorkbook(dataInputStream);
} catch (IOException e) {
e.printStackTrace();
}
// 获取第一个表单Sheet
XSSFSheet sheetAt = sheets.getSheetAt(0);
//默认第一行为标题行,i = 0
XSSFRow titleRow = sheetAt.getRow(0);
// 循环获取每一行数据
for (int i = 1; i < sheetAt.getPhysicalNumberOfRows(); i++) {
XSSFRow row = sheetAt.getRow(i);
// 读取每一格内容
StringBuilder sb = new StringBuilder();
for (int index = 0; index < row.getPhysicalNumberOfCells(); index++) {
XSSFCell titleCell = titleRow.getCell(index);
XSSFCell cell = row.getCell(index);
cell.setCellType(CellType.STRING);
if (cell.getStringCellValue().equals("")) {
continue;
}
sb.append(cell);
}
System.out.println(i + "\t" + sb);
}
复制代码
读大 excel 文件时候推荐使用
!-- 读取大量excel数据时使用 -->
<dependency>
<groupId>com.monitorjbl</groupId>
<artifactId>xlsx-streamer</artifactId>
<version>2.1.0</version>
</dependency>
复制代码
package com.platform.modules.admin.controller;
import com.monitorjbl.xlsx.StreamingReader;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import java.io.File;
import java.io.FileInputStream;
import java.util.*;
public class ReadBigExcel {
public static Map<String, List<String>> test(File file) throws Exception{
FileInputStream in = new FileInputStream(file);
Map<String,List<String>> mapData = new HashMap<String, List<String>>();
Workbook wk = StreamingReader.builder()
.rowCacheSize(100) //缓存到内存中的行数,默认是10
.bufferSize(4096) //读取资源时,缓存到内存的字节大小,默认是1024
.open(in); //打开资源,必须,可以是InputStream或者是File,注意:只能打开XLSX格式的文件
int sheetNums = wk.getNumberOfSheets();
for(int i = 0 ; i < sheetNums;i ++){
List<String> sheetData = new ArrayList<String>();
Sheet sheet = wk.getSheetAt(i);
String sheetName = wk.getSheetName(i);
//遍历所有的行
int k = 0;
for (Row row : sheet) {
StringBuilder sb = new StringBuilder();
//遍历所有的列
for (Cell cell : row) {
sb.append(cell.getStringCellValue());
}
System.out.println(k++ + "\t" + sb.toString());
}
}
return mapData;
}
public static void main(String[] args) throws Exception {
File file = new File("C:\\Users\\Lenovo\\Desktop\\数据导入模板及填写格式 (2).xlsx");
long t1 = new Date().getTime();
test(file);
long t2 = new Date().getTime();
System.out.println((t2-t1)/1000 + "秒");
}
}
复制代码
EasyExcel
EasyExcel 是一个阿里出品的开源项目 ,看名字就能看出这个项目是为了让你更加简单的操作 Excel。另外 EasyExcel 还解决了 poi 内存溢出问题,修复了一些并发情况下一些 bug。
github 地址:https://github.com/alibaba/easyexcel
参考
http://t.zoukankan.com/edda-p-14191959.html
Share
最近在看左耳听风专栏,关于如何学习技术知识进行了总结
如何面对枯燥、大量的技术知识
要承认这个知识对我来说太高级了,目前没有找到切入点,不知道能用在哪
去找一下其应用场景,先从简单的应用学起(如何应用,适用场景),先从感性认识,再到理论基础学习
带着相关问题去学习,带着解决的东西学习,完成会有成就感(学习需要反馈,成就感才能持续)
总结学习知识并 分享学习心得、过程、笔记、代码,最好找到同伴(持续学习动力)
找牛人帮忙讲解指导也是好的选择
如何快速学习并掌握
找到关键路径,先学习主干知识,构建出关键路径,形成知识地图
认真阅读技术文档、用户手册
用不同的方式学习同一个东西(。比如:通过看书,听课,创建脑图,写博客,讲课,解决实际问题,等等。)
总结压缩信息,关注的是关键知识点。学习本质和原理的知识
用教的方式学习,学以致用,不强求记忆,找到方法,去推导知识或者答案
实践出真知坚持不懈
学习技术知识模版
这个技术知识出现的背景是什么,它要达成什么样的目标,要解决的是什么问题
优点和缺点是什么,它为了解决问题 如何做了 tradeoff 取舍,带来哪些新的问题
适用场景有哪些(技术场景、业务场景)
技术的组成部分和关键点是什么,核心思想和核心组件是什么。 包含哪些关键技术点(找到关键路径,先学习主干知识,构建出关键路径,形成知识地图)
底层原理与关键实现
和已有的其他技术实现有什么区别(比如某个框架 或者存储技术)
把复杂问题用自己简单的语言进行描述,把我们学到的东西用自己的语言和理解重新组织并表达出来。 学习的开始阶段不急于总结,做结论。当对整个知识有了一定全面理解时候,在复习巩固的时候对知识进行回顾和重组会更好
要多看经典方法论图书,看别人如何总结归纳知识,可以进行模仿把自己学习的知识总结写出来,也可以写博客,或者讲给别人听,接收别人的批评与发奎
如何具有举一反三的能力
联想能力: 同一个事物不同的用法,其他相似或者相关的事物有哪些
抽象能力:解决问题的通用模型
自省能力:得到一个答案时候,站到自己的对立面找漏洞,获得全面的问题分析能力
在这方面,我对自己的训练如下。对于一个场景,制造出各种不同的问题或难题。对于一个问题,努力寻找尽可能多的解,并比较这些解的优劣。对于一个解,努力寻找各种不同的测试案例,以图让其健壮。
评论