基础算法记录(四)

基础算法记录四

字符串单词和标点符号顺序提取,禁止用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;
}
}
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页