数组题
1.给定一个数组nums,写一个函数将数组中的所有0挪到数组末尾而且维持其他所有非零元素相对位置不变
举例:nums[3,7,0,6,0,3,2] 函数运行后结果为nums=[3,7,6,3,2,0,0]
public class Solution {
public static void swap(int[] nums,int a,int b){
int temp=nums[a];
nums[a]=nums[b];
nums[b]=temp;
}
public static void moveZeroes(int[] nums){
int k=0;
//nums中,[1....k)的元素均为非0元素
//遍历到第i个元素后保证[0,....i]中的所有非0元素都按照顺序排列在[0,...k)中
//同时[k,...i]都为0
for(int i=0;i<nums.length;i++){
if(nums[i]!=0){ //nums[i]不为0
swap(nums,k,i);
k++;
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int nums[]={4,5,0,7,0,6,9};
moveZeroes(nums);
for(int i=0;i<nums.length;i++){
System.out.print(nums[i]+" ");
}
}
}
2.给定一个数组nums和一个数值val,将数组中的所有等于val的元素删除,并返回剩余元素的个数
public static int removeElement(int[] nums, int numsSize, int val){
int count = 0;//计算与val值不等的元素
int i = 0;
while (i<numsSize )//i和count初始相同 如果和val相等那么 i++
//那么和val相同的值就在count位,直到下次第i位不等的值。替换第count位
{
if (nums[i] != val)
{
nums[count] = nums[i];//用和val不同的数把前面和val相同的覆盖
count++;
}
i++;
}
System.out.println("移除后的元素:");
for (int j = 0; j < count; j++)
{
System.out.println(nums[j]);
}
return count;
}
public static void main(String[] args) {
int num[] = { 0, 1, 2, 2, 3, 0, 4, 2 };
int a = 2;
int b= removeElement(num, num.length, a);
System.out.println("新的长度为:" +b);
}
3.给定一个有序数组nums,对数组中的元素去重,使得原数组中的每个元素最多保留两个,返回去重后的数组长度
public static int removeElement(int[] nums, int numsSize, int rs){
int count = 0;
int i = 0;
int temp[]=new int[numsSize];
while (i<numsSize )
//那么和val相同的值就在count位,直到下次第i位不等的值。替换第count位
{
if(temp[nums[i]]<rs){
nums[count]=nums[i];
count++;
temp[nums[i]]++;
}
i++;
}
System.out.println("移除后的元素:");
for (int j = 0; j < count; j++)
{
System.out.println(nums[j]);
}
return count;
}
public static void main(String[] args) {
int num[] = { 1, 2, 2, 2 ,3, 3, 4 };
int a = 2;
int b= removeElement(num, num.length, a);
System.out.println("新的长度为:" +b);
}
4.给定一个有n个元素的数组,数组中的元素只有0,1,2三种可能,为这个数组排序
public static void swap(int[] nums,int a,int b){
int temp=nums[a];
nums[a]=nums[b];
nums[b]=temp;
}
//时间复杂度:O(n)
//空间复杂度:O(1) 三路快排思想
public static void sortedColors(int[] nums){
int zero=-1; //nums[0....zero]==0
int two=nums.length; //nums[two..n-1]==2
for(int i=0;i<two;){
if(nums[i]==1){
i++;
}else if(nums[i]==2){
swap(nums,i,--two);
}else{
assert(nums[i]==0); //nums[i]==0必须等于0
swap(nums,++zero,i++);
}
}
}
public static void main(String[] args) {
int num[] = { 2,1,1,0,2,1,1,0,1,2};
sortedColors(num);
for (int i : num) {
System.out.println(i);
}
}
对撞指针
2.给定一个有序整型数组和一个整型数target,在其中寻找两个元素的和为target,返回这两个元素的索引。
可以定义两个索引 i,j,他们分别指向数组的开头和结尾,判断他们的和是否为target,是则返回,否则判断是比target小还是大,小则 i索引右移,因为数组是有序的,所以此时他们的和增大了,再次比较,若和比target大,则 j 左移,此时他们和减小了,再次和target比较,直到找到两个目标元素。code:
public class Solution {
public static void twoSum(int[] nums,int target){
int l=0;
int r=nums.length-1;
while(l<r){
if((nums[l]+nums[r])==target){
System.out.println("目标索引:"+l+" "+r);
return;
}else if((nums[l]+nums[r])<target){
l++;
}else{
r--;
}
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int nums[]={0,2,5,7,9,12,34,40,46};
twoSum(nums,49);
}
}
###双索引技术(滑动窗口)
####3.给定一个整型数组和数字s,找到数组中最短的一个连续子数组(即数组中的元素都是相邻的),使得连续子数组的数字和大于等于s,返回这个数组的长度
public class Solution {
public static void swap(int[] nums,int a,int b){
int temp=nums[a];
nums[a]=nums[b];
nums[b]=temp;
}
public static int minSubArrayLen(int[] nums,int target){
int l=0,r=-1;//nums[l...r]为我们的滑动窗口
int sum=0; //子数组和
int res=nums.length+1; //返回的最短子数组长度
while(l<nums.length){
//r<nums.length-1是为了防止越界,后面有++r操作
if(r<nums.length-1&&sum<target){
sum+=nums[++r];
}else{
sum-=nums[l++];
}
//在滑动窗口右边界向右挪动后或左边界向右挪动后
//都判断一次子数组和是否>=target
if(sum>=target){
res=Math.min(res,r-l+1);
}
}
if(res==nums.length+1){
return 0;
}
return res;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int nums[]={0,2,5,9,1,0,2,10,4,1,1,11};
System.out.println(minSubArrayLen(nums,15));
}
}
####4.在一个字符串中寻找没有重复字母的最长子串
如:“abcabcbb”,结果为"abc"
如:“bbbbbb”,结果为"b"
如:“pwwkew”,结果为"wke"
code:
public class Solution {
public static byte charToByteAscii(char ch){
byte byteAscii = (byte)ch;
return byteAscii;
}
public static int lenOfLongestString(String s){
int l=0,r=-1; //滑动窗口为s[l.....r]
int freq[]=new int[256];
int res=0; //最长没有重复字符的子字符串长度
while(l<s.length()){
if(r+1<s.length()&&freq[charToByteAscii(s.charAt(r+1))]==0){ //s.charAt(r+1)字符暂没重复
freq[charToByteAscii(s.charAt(++r))]++;
}else{
freq[charToByteAscii(s.charAt(l++))]--;
}
res=Math.max(res, r-l+1);
}
return res;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String s="sdfggbttryytn";
System.out.println(lenOfLongestString(s));
}
}
####5.给定一个字符串S和T,在S中寻找一个最短的子串,包含T中的所有字符
如:S=“ADOBECODEBANC”;T=“ABC”
结果为"BANC"
code:
public class Solution {
public static boolean contain(String s,String t){
boolean flag=true;
for(int i=0;i<t.length();i++){
if(!s.contains(t.substring(i, i+1))){
flag=false;
}
}
return flag;
}
public static int lenOfShortestString(String S,String T){
int l=0,r=1; //滑动窗口为s[l.....r]
int res=S.length(); //最短包含目标字符串的子字符串长度
while(l<S.length()){
if(r<S.length()&&!contain(S.substring(l, r),T)){ //不包含
r++;
}else{ //包含
l++;
}
if(contain(S.substring(l, r),T)){
res=Math.min(res, r-l);
}
}
return res;
}
public static void main(String[] args) {
System.out.println(lenOfShortestString("ACBADINDAAB","ADB"));
}
}
###HashMap、HashSet在算法中的运用
####6.给出一个整型数组nums,返回数组中的两个索引,使得nums[i]+nums[j]=target,两个索引不能相等
如:nums[5,1,3,5,8,7],target=8
返回[0,2] [2,3]
上面有一个相似的题目,但是上面那题的数组是有序的,通过对撞指针解决问题,而这题的数组没规定是有序的
public class Solution {
public static void twoSum(int[] nums,int target){
Map<Integer,Integer> record=new HashMap<>();
for(int i=0;i<nums.length;i++){
int complement=target-nums[i];
if(record.get(complement)!=null){
System.out.println(i+" "+record.get(complement));
}else{
record.put(nums[i], i);
}
}
}
public static void main(String[] args) {
int nums[]={3,5,6,6,6,233,5,6,89,1};
twoSum(nums,11);
}
}
####7.给出一个整型数组和一个整数K,是否存在索引i和j,使得nums[i]==nums[j]且i和j的差不超过k
code:
public class Solution {
public static boolean containsDuplicate(int[] nums,int k){
Set<Integer> record=new HashSet<>();
for(int i=0;i<nums.length;i++){
if(record.contains(nums[i])){
return true;
}
record.add(nums[i]);
//保持record最多有k个
if(record.size()==k+1){
record.remove(nums[i-k]);
}
}
return false;
}
public static void main(String[] args) {
int nums[]={3,5,6,233,5,6,89,1};
System.out.println(containsDuplicate(nums,3));
}
}
###链表算法
链表和数组都是一种顺序结构,但是使用数组我们可以随机访问数组中任一元素,只要给出索引就能以O(1)的时间复杂度找到那个元素。而链表不支持,我们只能从链表的头节点开始循着next指针依次向后寻找下一个元素
####8.反转一个链表
code:
public class Solution {
static class Node{
int val;
Node next;
Node(int x){
val=x;
next=null;
}
}
public static Node createLinkedList(int arr[],int n){
if(n==0){
return null;
}
Node head=new Node(arr[0]);
Node curNode=head;
for(int i=1;i<n;i++){
curNode.next=new Node(arr[i]);
curNode=curNode.next;
}
return head;
}
public static Node reverseList(Node head){
Node pre=null;
Node cur=head;
while(cur!=null){
Node next=cur.next;
cur.next=pre;
pre=cur;
cur=next;
}
return pre;
}
public static void printList(Node head){
Node node=head;
while(node!=null){
System.out.print(node.val+"->");
node=node.next;
}
System.out.print("NULL");
}
public static void main(String[] args) {
int nums[]={3,4,7,2,9,6,1};
printList(createLinkedList(nums,nums.length));
System.out.println();
printList(reverseList(createLinkedList(nums,nums.length)));
}
}
//结果:
//3->4->7->2->9->6->1->NULL
//1->6->9->2->7->4->3->NULL
####9.给出一个有序链表,删除其中所有重复元素,使得每个元素只保留一次
如:1->1->2,返回1->2
如:1->1->2->3->3,返回1->2->3
code:
public class Solution {
.............
public static Node removeDuplicateList(Node head){
if(head==null){
return null;
}
Node cur=head;
Node nextUnequal=cur.next;
while(nextUnequal!=null){
if(cur.val==nextUnequal.val){
nextUnequal=nextUnequal.next;
if(nextUnequal==null){
cur.next=null;
}
}else{
cur.next=nextUnequal;
cur=nextUnequal;
}
}
return head;
}
public static void printList(Node head){
Node node=head;
while(node!=null){
System.out.print(node.val+"->");
node=node.next;
}
System.out.print("NULL");
}
public static void main(String[] args) {
int nums[]={1,1,1,2,2,2,3,4,4};
printList(createLinkedList(nums,nums.length));
System.out.println();
printList(removeDuplicateList(createLinkedList(nums,nums.length)));
}
}
//结果:
//1->1->1->2->2->2->3->4->4->NULL
//1->2->3->4->NULL
####10.给定一个链表,对于每两个相邻的节点,交换他们的位置
如:1->2->3->4->null
返回:2->1->4->3->null
只能对节点进行操作,不能直接修改节点的值
code:
public class Solution {
..............
public static Node swapPairs(Node head){
Node dummyNode=new Node(0); //虚拟头节点
dummyNode.next=head;
Node p=dummyNode;
while((p.next!=null)&&(p.next.next!=null)){
Node node1=p.next;
Node node2=node1.next;
Node next=node2.next;
node2.next=node1;
node1.next=next;
p.next=node2;
p=node1;
}
return dummyNode.next;
}
..............
public static void main(String[] args) {
int nums[]={1,2,3,4,5,6,7,8};
printList(createLinkedList(nums,nums.length));
System.out.println();
printList(swapPairs(createLinkedList(nums,nums.length)));
}
}
//1->2->3->4->5->6->7->8->NULL
//2->1->4->3->6->5->8->7->NULL
####11.给定一个链表,每K个节点为一组,反转每一组的K个节点,K为正整数且小于等于链表长度。如果链表长度不是K的整数倍,则剩余部分不需要进行反转。
如:1->2->3->4->5->NULL
若K=2,则结果为:2->1->4->3->5->NULL
若K=3,结果为:3->2->1->4->5->NULL
若K=5,结果为:5->4->3->2->1->NULL
code:
public class Solution {
.................
public static boolean isNull(Node p,int k){
for(int i=0;i<k;i++){
p=p.next;
if(p==null){
return true;
}
}
return false;
}
public static Node swapPairs(Node head,int k){
Node dummyNode=new Node(0); //虚拟头节点
dummyNode.next=head;
Node p=dummyNode;
Node p1=p;
Node[] node=new Node[k+1];
while(!isNull(p,k)){
for(int i=0;i<k+1;i++){
node[i]=p1.next;
p1=p1.next;
}
for(int i=0;i<k;i++){
if(i==0){
node[i].next=node[k];
}else{
node[i].next=node[i-1];
}
}
p.next=node[k-1];
p=node[0];
p1=p;
}
return dummyNode.next;
}
.............
public static void main(String[] args) {
int nums[]={1,2,3,4,5,6,7};
printList(createLinkedList(nums,nums.length));
System.out.println();
printList(swapPairs(createLinkedList(nums,nums.length),7));
}
}
//1->2->3->4->5->6->7->NULL
//7->6->5->4->3->2->1->NULL
####12.用O(nlogn)时间复杂度的算法为链表排序
当为链表进行排序时,由于不能随机的访问链表中的元素,那么大多数的O(nlogn)排序算法是不适用的,而归并排序在排序过程中是不需要索引在数组中来回跳动的,下面我抽出了对链表进行归并排序中的最重要的一部分展示:对两个排好序的链表进行合并,合并成一个有序的链表。剩下的就是不断递归合并,以实现最终的算法
code:
public class Solution {
................
public static Node mergeList(Node head,Node l,Node r){
Node dummyNode=new Node(0); //虚拟头节点
dummyNode.next=head;
Node curNode=dummyNode;
while(curNode.next!=null){
if(l.val<=r.val){
curNode.next=l;
curNode= curNode.next;
l=l.next;
if(l==null){
curNode.next=r;
curNode=curNode.next;
}
}else{ //l.val>r.val
curNode.next=r;
curNode= curNode.next;
r=r.next;
if(r==null){
curNode.next=l;
curNode=curNode.next;
}
}
}
return dummyNode.next;
}
...............
public static void main(String[] args) {
int nums[]={4,7,5,2,1,3,6};
int num1[]={4,5,7};
int num2[]={1,2,3,6};
Node head=createLinkedList(nums,nums.length);
printList(head);
Node l=createLinkedList(num1,num1.length);
Node r=createLinkedList(num2,num2.length);
System.out.println();
printList(l);
System.out.println();
printList(r);
System.out.println();
printList(mergeList(head,l,r));
}
}
//4->7->5->2->1->3->6->NULL
//4->5->7->NULL
//1->2->3->6->NULL
//1->2->3->4->5->6->7->NULL
####13.删除链表中某一节点
给出链表中某一待删除节点的索引,删除该节点
code:
public class Solution {
..................
public static void delNode(Node node){
if(node==null){
return;
}
if(node.next==null){
node=null;
}
node.val=node.next.val;
node.next=node.next.next;
}
..................
public static void main(String[] args) {
int nums[]={4,7,5,2,1,3,6};
Node head=createLinkedList(nums,nums.length);
printList(head);
Node curNode=head;
while(curNode!=null){
if(curNode.val==5){
delNode(curNode);
break;
}
curNode=curNode.next;
}
System.out.println();
printList(head);
}
}
//结果:
//删除前 :4->7->5->2->1->3->6->NULL
//删除后 :4->7->2->1->3->6->NULL
###栈和队列
栈和递归算法的关系:常用自定义栈模拟系统栈,写出非递归程序(常见递归算法就是利用的系统栈)
栈顶元素反映了在嵌套的层次关系中,最近的需要匹配的元素
####14.给出一个嵌套的整型列表。列表中的项或为一个整数,或为一个整型列表。设计一个迭代器,遍历这个整型列表中的所有整数。
-如[[1,1],2,[1,1]] ,遍历结果为 1,1,2,1,1
-如[1,[4,[6]]] ,遍历结果为1,4,6
code:
类NestInteger:
public class NestInteger {
private int val;
private boolean isInteger=false;
private List<NestInteger> nestList;
public NestInteger(int val) {
this.val = val;
this.isInteger = true;
this.nestList = null;
}
public NestInteger( List<NestInteger> nestList) {
this.val = 0;
this.isInteger = false;
this.nestList = nestList;
}
public boolean isInteger(){
return isInteger;
}
public int getInteger(){
return val;
}
public List<NestInteger> getList(){
return nestList;
}
}
自定义迭代器:
public class NestIterator implements Iterable<NestInteger>,Iterator<NestInteger>{
private List<NestInteger> nestList =null;
private List<NestInteger> nestList2 =new ArrayList<>();
private int index=0;
public NestIterator(List<NestInteger> nestList) {
this.nestList = nestList;
}
@Override
public boolean hasNext() {
return index<nestList2.size();
}
@Override
public NestInteger next() {
return nestList2.get(index++);
}
@Override
public Iterator<NestInteger> iterator() {
Stack s=new Stack<NestInteger>();
for(int i=nestList.size()-1;i>=0;i--){
s.push(nestList.get(i));
}
while(!s.isEmpty()){
NestInteger nestInteger=(NestInteger) s.peek();
s.pop();
if(nestInteger.isInteger()){
nestList2.add(nestInteger);
}else{
List<NestInteger> nests=nestInteger.getList();
for(int j=nests.size()-1;j>=0;j--){
s.push(nests.get(j));
}
}
}
return this;
}
}
测试类:
public class Solution {
public static void main(String[] args) {
List<NestInteger> nests=Arrays.asList(new NestInteger(2),new NestInteger(3));
List<NestInteger> nests2=Arrays.asList(new NestInteger(5));
List<NestInteger> nests3=Arrays.asList(new NestInteger(1),new NestInteger(nests),new NestInteger(nests2));
NestIterator iterator=new NestIterator(nests3);
for(NestInteger in:iterator){
System.out.print(in.getInteger()+" ");
}
}
}
//结果: 1 2 3 5