基础算法记录四
字符串单词和标点符号顺序提取,禁止用split
例如 输入:{“Oh, a good day!”}
输出:{“Oh”, “,”, “good”, “day”, “!”}
这是今天网易有道二面面试手撕代码的题,题是不难,注意的是细节,当时在纸上写出bug来了,用的时间也不是满意,总之应该是凉了,自己手撕代码的能力确实该提高。题目思路就是遍历字符,记录按条件截取字符串,注意边界问题即可
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* 顺序提取字符串{Oh, a good day!}输出{"Oh",",","a","good","day","!"}
* @author Shinelon
*
*/
public class TestSplitString {
public static void main(String [] args) {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
TestSplitString test = new TestSplitString();
String[] rs = test.dataSegement(str);
for(int i=0;i<rs.length;i++) {
System.out.println(rs[i]);
}
}
public String [] dataSegement(String str) {
char[] array = str.toCharArray();
List<String> list = new ArrayList<>();
int index = 0;
for(int i=0;i<array.length;i++) {
if(array[i]>='A'&&array[i]<='Z'||array[i]>='a'&&array[i]<='z') {
}else if(array[i]==' ') {
String string = str.substring(index,i);
index = i+1;
list.add(string);
}else {
String string1 = str.substring(index,i);
String string2 = str.substring(i,i+1);
if(i+1<array.length&&array[i+1]==' ') {
index = i+2;
i++;
}
index = i+1;
list.add(string1);
list.add(string2);
}
}
String[] rs = new String[list.size()];
for(int i=0;i<list.size();i++) {
rs[i] = list.get(i);
}
return rs;
}
}
京东笔试题目:找出X*Y=某数 X奇数Y偶数,Y最小偶数 注意用Long,我这里没有。因为最大数2^63
首先奇数偶数必然是偶数,排除奇数,其次偶数最小,即奇数最大,倒序找出最大技术因数就可以,还要注意long问题,掉坑了 *
import java.util.Scanner;
/**
* JD笔试
* 找出X*Y=某数 X奇数Y偶数,Y最小偶数 注意用long。因为最大数2^63
* @author Shinelon
*
*/
public class FindNum {
public static void main(String [] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
long[] nums = new long[n];
for(int i=0;i<n;i++) {
nums[i]=sc.nextLong();
}
sc.close();
FindNum find = new FindNum();
find.findRs(nums);
}
public void findRs(long [] nums) {
for(int j=0;j<nums.length;j++) {
if(nums[j]%2!=0) {
System.out.println("No");
return ;
}else {
long temp = nums[j]-1;
while(nums[j]%temp!=0&&temp>=1) {
temp -=2;
}
long left = temp;
long right = nums[j]/temp;
System.out.println(left+" "+right);
}
}
}
}
判断栈的正确序列问题
比如12345 45321是正确出栈序列,而45123不是,传入两个数组,一个入栈,判断另一个是否是合法出栈
可以模拟栈的入栈出栈,假定给的判断序列是正确的,那么只要根据入栈数组入栈,后按着出栈数组出栈,矛盾了就是错了,需要一个辅助栈来模拟。根据入栈数组尽管入栈,不过每次入栈后判断当前元素是否按出栈数组需要出栈,如果是就出栈,出栈数组指针后移,当数组遍历完毕,就是完成了当前所有入栈并且这个过程中该处的已经出了,然后只管出栈,出栈时判断和出栈数组栈顶元素是否相同,相同指针后移。最后如果是正确的,则出栈数组指针一定刚好越界
import java.util.Scanner;
import java.util.Stack;
/**
* 判断栈的正确序列问题 12345 45321 45123...
* @author Shinelon
*
*/
public class Solution {
public static void main(String [] args){
Solution solution = new Solution();
Scanner sc = new Scanner(System.in);
int size = sc.nextInt();
int [] pushA = new int[size];
int [] popA = new int[size];
for(int i=0;i<size;i++) {
pushA[i] = sc.nextInt();
}
for(int i=0;i<size;i++) {
popA[i] = sc.nextInt();
}
Solution s = new Solution();
boolean rs = s.IsPopOrder(pushA, popA);
System.out.println(rs);
}
/**
* 用一个辅助栈,假设序列是正确的,根据序列模拟出栈,若辅助栈空而序列遍历完,说明没矛盾
* @param pushA
* @param popA
* @return
*/
public boolean IsPopOrder(int [] pushA,int [] popA) {
Stack<Integer> temp = new Stack<>();
int k=0;
for(int i=0;i<pushA.length;i++) {
temp.push(pushA[i]);
if(temp.peek()==popA[0]) {
temp.pop();
k++;
}
}
while(!temp.isEmpty()) {
int t =temp.pop();
if(t==popA[k]) {
k++;
}
}
if(k==popA.length) {
return true;
}else {
return false;
}
}
public int getIndexFromA(int [] A,int num) {
for(int j=0;j<A.length;j++) {
if(num==A[j]) {
return j;
}
}
return -1;
}
}
移动0 比如 042013 变为421300
移动所有非0,最后补0,遍历时记录几个0,然后移动几位
import java.util.Scanner;
/**
* 移动0,保留原来顺序,比如 0 1 4 3 0 为 1 4 3 0 0
* @author Shinelon
*
*/
public class MoveZero {
public static void main(String [] args) {
Scanner sc = new Scanner(System.in);
MoveZero move = new MoveZero();
int n = sc.nextInt();
int nums [] = new int[n];
for(int k=0;k<n;k++) {
nums[k] = sc.nextInt();
}
sc.close();
move.moveZeroes(nums);
for(int k=0;k<n;k++) {
System.out.println(nums[k]);
}
}
public void moveZeroes(int[] nums) {
int count_zero = 0;
for(int i=0;i<nums.length;i++) {
if(nums[i]==0) {
count_zero++;
}else if(count_zero>0){
nums[i-count_zero] = nums[i];
}
}
for(int j=nums.length-count_zero;j<nums.length;j++) {
nums[j] = 0;
}
}
}
合并有序链表
public class MergerTwoLinks {
static ListNode l1;
static ListNode l2;
static ListNode head;
class ListNode{
int val;
ListNode next;
}
public static void main(String [] args) {
MergerTwoLinks merge = new MergerTwoLinks();
merge.initList();
merge.addNode(l1, 2);
merge.addNode(l1, 4);
merge.addNode(l2, 3);
merge.addNode(l2, 4);
ListNode rs = merge.mergeTwoLists(l1, l2);
while(rs!=null) {
System.out.print(rs.val);
rs = rs.next;
}
}
/**
* 思路,将两个链表表头小的节点作为合并后的头结点,然后指针后移,循环比较两个链表的头节点
* 小的插到合并后的链表后面直到旧的链表遍历结束
* @param l1
* @param l2
* @return
*/
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode temp = null;
if(l1.val<=l2.val && head==null) {
head = l1;
temp = head;
l1 = l1.next;
}else if(l1.val>l2.val && head==null) {
head = l2;
temp = head;
l2 = l2.next;
}
while(l1!=null||l2!=null) {
if(l1==null) {
temp.next = l2;
//退出循环,不然死循环
break;
}else if(l2==null){
temp.next = l1;
break;
}else {
if(l1.val<=l2.val) {
temp.next = l1;
temp = temp.next;
l1 = l1.next;
}else {
temp.next = l2;
temp = temp.next;
l2 = l2.next;
}
}
}
return head;
}
public void initList() {
l1 = new ListNode();
l1.val=1;
l2 = new ListNode();
l2.val=1;
}
public void addNode(ListNode l,int x) {
while(l.next!=null) {
l = l.next;
}
l.next = new ListNode();
l.next.val = x;
}
}
三数之和为0
双指针,注意去除重复
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
/**
* 找出数组三数之和为0的元素,不重复,双指针
* @author Shinelon
*
*/
public class TestThreeNum {
public static void main(String [] args) {
Scanner sc = new Scanner(System.in);
TestThreeNum test = new TestThreeNum();
int n = sc.nextInt();
int [] nums = new int[n];
for(int i=0;i<n;i++) {
nums[i]=sc.nextInt();
}
sc.close();
//先排序
Arrays.sort(nums);
List<List<Integer>> rs = test.threeSum(nums);
System.out.println(rs.toString());
}
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> outList = new ArrayList<>();
//如果大于0都是正数,不可能
if(nums[0]>0) {
return outList;
}
for(int i=0;i<nums.length-2;i++) {
//去除重复
if(i>0&&nums[i]==nums[i-1]) {
continue;
}
int j=i+1;
int k=nums.length-1;
while(j<k) {
if(nums[k]+nums[j]+nums[i]>0) {
k--;
}else if(nums[k]+nums[j]+nums[i]<0){
j++;
}else {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[k]);
outList.add(list);
//继续遍历
k--;
j++;
//去除重复
while(j<k&&nums[j]==nums[j-1]) {
j++;
}
//去除重复
while(j<k&&nums[k]==nums[k+1]) {
k--;
}
}
}
}
return outList;
}
}
最长不重复字串
利用HashMap,key为字符,value为上一次出现的索引,若已经存在,说明当前索引-上次索引为这一段不重复字串长度,之后更新其值,字串开始的索引在刚刚上一次那里+1,即新的不重复字串的开始
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
/**
* 最长不重复子串O(n)
* HashMap,key为字符,value为索引。当map中不存在时,直接放入,否则取出上一个索引
* 当前减去上一个索引即为当前不重复的最长长度,然后从上一个重复的数的下一个索引开始新一轮比较,
* 也就是去除重复因素的影响,将开始start+1索引。若不存在,放入之后更新长度值,也就是-start+1
* @author Shinelon
*
*/
public class TestMaxChildString {
public static void main(String [] args) {
TestMaxChildString test = new TestMaxChildString();
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
sc.close();
int rs = test.lengthOfLongestSubstring(s);
System.out.println(rs);
}
public int lengthOfLongestSubstring(String s) {
char [] c = s.toCharArray();
Map<Character,Integer> map = new HashMap<>();
int max=0;//最大值
int start=0;//寻找不重复字串长度开始的索引
for(int i=0;i<c.length;i++) {
if(map.containsKey(c[i])) {
//temp>=start,说明在寻找的合法范围内
int temp =map.get(c[i]);
if(temp>=start) {
//更新,两个之间的差值即为不重复长度
max = Math.max(i-temp,max);
//后移一位,因为前面已经重复了,构造新的不重复串并继续比较,后面可能出现更长的不重复
start = temp+1;
//更新当前的索引,消除前面那个重复数的影响,因为构造的是不重复的新串
map.put(c[i], i);
}else {//不存在,则放入并更新值
map.put(c[i], i);
int rs = i-start+1;
max = Math.max(max, rs);
}
}else {
map.put(c[i], i);
int rs = i-start+1;
max = Math.max(max, rs);
}
}
return max;
}
}